@helpwave/hightide
Version:
helpwave's component and theming library
1 lines • 51.3 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/components/date/DatePicker.tsx","../../../src/hooks/useLanguage.tsx","../../../src/hooks/useLocalStorage.tsx","../../../src/hooks/useTranslation.ts","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/util/date.ts","../../../src/components/Button.tsx","../../../src/components/date/YearMonthPicker.tsx","../../../src/components/Expandable.tsx","../../../src/components/date/DayPicker.tsx"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport { ArrowDown, ArrowUp, ChevronDown } from 'lucide-react'\nimport type { Languages } from '../../hooks/useLanguage'\nimport type { PropsForTranslation } from '../../hooks/useTranslation'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { noop } from '../../util/noop'\nimport { addDuration, isInTimeSpan, subtractDuration } from '../../util/date'\nimport clsx from 'clsx'\nimport { SolidButton, TextButton } from '../Button'\nimport { useLocale } from '../../hooks/useLanguage'\nimport type { YearMonthPickerProps } from './YearMonthPicker'\nimport { YearMonthPicker } from './YearMonthPicker'\nimport type { DayPickerProps } from './DayPicker'\nimport { DayPicker } from './DayPicker'\n\ntype DatePickerTranslation = {\n today: string,\n}\n\nconst defaultDatePickerTranslation: Record<Languages, DatePickerTranslation> = {\n en: {\n today: 'Today',\n },\n de: {\n today: 'Heute',\n }\n}\n\ntype DisplayMode = 'yearMonth' | 'day'\n\nexport type DatePickerProps = {\n value?: Date,\n start?: Date,\n end?: Date,\n initialDisplay?: DisplayMode,\n onChange?: (date: Date) => void,\n dayPickerProps?: Omit<DayPickerProps, 'displayedMonth' | 'onChange' | 'selected'>,\n yearMonthPickerProps?: Omit<YearMonthPickerProps, 'displayedYearMonth' | 'onChange' | 'start' | 'end'>,\n className?: string,\n}\n\n/**\n * A Component for picking a date\n */\nexport const DatePicker = ({\n overwriteTranslation,\n value = new Date(),\n start = subtractDuration(new Date(), { years: 50 }),\n end = addDuration(new Date(), { years: 50 }),\n initialDisplay = 'day',\n onChange = noop,\n yearMonthPickerProps,\n dayPickerProps,\n className = ''\n }: PropsForTranslation<DatePickerTranslation, DatePickerProps>) => {\n const locale = useLocale()\n const translation = useTranslation(defaultDatePickerTranslation, overwriteTranslation)\n const [displayedMonth, setDisplayedMonth] = useState<Date>(value)\n const [displayMode, setDisplayMode] = useState<DisplayMode>(initialDisplay)\n\n useEffect(() => {\n setDisplayedMonth(value)\n }, [value])\n\n return (\n <div className={clsx('col gap-y-4', className)}>\n <div className=\"row items-center justify-between h-7\">\n <TextButton\n className={clsx('row gap-x-1 items-center cursor-pointer select-none', {\n 'text-disabled-text': displayMode !== 'day',\n })}\n onClick={() => setDisplayMode(displayMode === 'day' ? 'yearMonth' : 'day')}\n >\n {`${new Intl.DateTimeFormat(locale, { month: 'long' }).format(displayedMonth)} ${displayedMonth.getFullYear()}`}\n <ChevronDown size={16}/>\n </TextButton>\n {displayMode === 'day' && (\n <div className=\"row justify-end\">\n <SolidButton\n size=\"small\"\n color=\"primary\"\n disabled={!isInTimeSpan(subtractDuration(displayedMonth, { months: 1 }), start, end)}\n onClick={() => {\n setDisplayedMonth(subtractDuration(displayedMonth, { months: 1 }))\n }}\n >\n <ArrowUp size={20}/>\n </SolidButton>\n <SolidButton\n size=\"small\"\n color=\"primary\"\n disabled={!isInTimeSpan(addDuration(displayedMonth, { months: 1 }), start, end)}\n onClick={() => {\n setDisplayedMonth(addDuration(displayedMonth, { months: 1 }))\n }}\n >\n <ArrowDown size={20}/>\n </SolidButton>\n </div>\n )}\n </div>\n {displayMode === 'yearMonth' ? (\n <YearMonthPicker\n {...yearMonthPickerProps}\n displayedYearMonth={value}\n start={start}\n end={end}\n onChange={newDate => {\n setDisplayedMonth(newDate)\n setDisplayMode('day')\n }}\n />\n ) : (\n <div>\n <DayPicker\n {...dayPickerProps}\n displayedMonth={displayedMonth}\n start={start}\n end={end}\n selected={value}\n onChange={date => {\n onChange(date)\n }}\n />\n <div className=\"mt-2\">\n <TextButton\n onClick={() => {\n const newDate = new Date()\n newDate.setHours(value.getHours(), value.getMinutes())\n onChange(newDate)\n }}\n >\n {translation.today}\n </TextButton>\n </div>\n </div>\n )}\n </div>\n )\n}\n\n/**\n * Example for the Date Picker\n */\nexport const ControlledDatePicker = ({\n value = new Date(),\n onChange = noop,\n ...props\n }: DatePickerProps) => {\n const [date, setDate] = useState<Date>(value)\n\n useEffect(() => setDate(value), [value])\n\n return (\n <DatePicker\n {...props}\n value={date}\n onChange={date1 => {\n setDate(date1)\n onChange(date1)\n }}\n />\n )\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from './useLocalStorage'\n\nexport const languages = ['en', 'de'] as const\nexport type Languages = typeof languages[number]\nexport const languagesLocalNames: Record<Languages, string> = {\n en: 'English',\n de: 'Deutsch',\n}\n\nexport const DEFAULT_LANGUAGE = 'en'\n\nexport type LanguageContextValue = {\n language: Languages,\n setLanguage: Dispatch<SetStateAction<Languages>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({ language: DEFAULT_LANGUAGE, setLanguage: (v) => v })\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Languages) => {\n const { language } = useLanguage()\n const mapping: Record<Languages, string> = {\n en: 'en-US',\n de: 'de-DE'\n }\n return mapping[overWriteLanguage ?? language]\n}\n\ntype ProvideLanguageProps = {\n initialLanguage?: Languages,\n}\n\nexport const ProvideLanguage = ({ initialLanguage, children }: PropsWithChildren<ProvideLanguageProps>) => {\n const [language, setLanguage] = useState<Languages>(initialLanguage ?? DEFAULT_LANGUAGE)\n const [storedLanguage, setStoredLanguage] = useLocalStorage<Languages>('language', initialLanguage ?? DEFAULT_LANGUAGE)\n\n useEffect(() => {\n if(language !== initialLanguage && initialLanguage){\n console.warn('LanguageProvider initial state changed: Prefer using useLanguages\\'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 languagesToTestAgainst = Object.values(languages)\n\n const matchingBrowserLanguages = window.navigator.languages\n .map(language => languagesToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n .filter(entry => entry !== undefined)\n\n if (matchingBrowserLanguages.length === 0) return\n\n const firstMatch = matchingBrowserLanguages[0] as Languages\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}\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}","import type { Languages } from './useLanguage'\nimport { useLanguage } from './useLanguage'\n\nexport type Translation<T> = Record<Languages, T>\n\ntype OverwriteTranslationType<Translation extends Record<string, unknown>> = {\n language?: Languages,\n translation?: Partial<Record<Languages, 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<Languages, 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 noop = () => undefined\n","export const equalSizeGroups = <T >(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\n/**\n * @param start\n * @param end inclusive\n * @param allowEmptyRange Whether the range can be defined empty via end < start\n */\nexport const range = (start: number, end: number, allowEmptyRange: boolean = false): number[] => {\n if (end < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start + 1 }, (_, index) => index + start)\n}\n\n/** Finds the closest match\n * @param list The list of all possible matches\n * @param firstCloser Return whether item1 is closer than item2\n */\nexport const closestMatch = <T >(list: T[], firstCloser: (item1: T, item2: T) => boolean) => {\n return list.reduce((item1, item2) => {\n return firstCloser(item1, item2) ? item1 : item2\n })\n}\n\n/**\n * returns the item in middle of a list and its neighbours before and after\n * e.g. [1,2,3,4,5,6] for item = 1 would return [5,6,1,2,3]\n */\nexport const getNeighbours = <T >(list: T[], item: T, neighbourDistance: number = 2) => {\n const index = list.indexOf(item)\n const totalItems = neighbourDistance * 2 + 1\n if (list.length < totalItems) {\n console.warn('List is to short')\n return list\n }\n\n if (index === -1) {\n console.error('item not found in list')\n return list.splice(0, totalItems)\n }\n\n let start = index - neighbourDistance\n if (start < 0) {\n start += list.length\n }\n const end = (index + neighbourDistance + 1) % list.length\n\n const result: T[] = []\n let ignoreOnce = list.length === totalItems\n for (let i = start; i !== end || ignoreOnce; i = (i + 1) % list.length) {\n result.push(list[i]!)\n if (end === i && ignoreOnce) {\n ignoreOnce = false\n }\n }\n return result\n}\n\nexport const createLoopingListWithIndex = <T >(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n if (length < 0) {\n console.warn(`createLoopingList: length must be >= 0, given ${length}`)\n } else if (length === 0) {\n length = list.length\n }\n\n const returnList: [number, T][] = []\n\n if (forwards) {\n for (let i = startIndex; returnList.length < length; i = (i + 1) % list.length) {\n returnList.push([i, list[i]!])\n }\n } else {\n for (let i = startIndex; returnList.length < length; i = i === 0 ? i = list.length - 1 : i - 1) {\n returnList.push([i, list[i]!])\n }\n }\n\n return returnList\n}\n\nexport const createLoopingList = <T >(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n return createLoopingListWithIndex(list, startIndex, length, forwards).map(([_, item]) => item)\n}\n\nexport const ArrayUtil = {\n unique: <T>(list: T[]): T[] => {\n const seen = new Set<T>()\n return list.filter((item) => {\n if (seen.has(item)) {\n return false\n }\n seen.add(item)\n return true\n })\n },\n\n difference: <T>(list: T[], removeList: T[]): T[] => {\n const remove = new Set<T>(removeList)\n return list.filter((item) => !remove.has(item))\n }\n}\n","import { equalSizeGroups } from './array'\n\nexport const monthsList = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] as const\nexport type Month = typeof monthsList[number]\n\nexport const weekDayList = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] as const\nexport type WeekDay = typeof weekDayList[number]\n\nexport const formatDate = (date: Date) => {\n const year = date.getFullYear().toString().padStart(4, '0')\n const month = (date.getMonth() + 1).toString().padStart(2, '0')\n const day = (date.getDate()).toString().padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nexport const formatDateTime = (date: Date) => {\n const dateString = formatDate(date)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n return `${dateString}T${hours}:${minutes}`\n}\n\nexport const getDaysInMonth = (year: number, month: number): number => {\n const lastDayOfMonth = new Date(year, month + 1, 0)\n return lastDayOfMonth.getDate()\n}\n\nexport type Duration = {\n years?: number,\n months?: number,\n days?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n}\n\nexport const changeDuration = (date: Date, duration: Duration, isAdding?: boolean): Date => {\n const {\n years = 0,\n months = 0,\n days = 0,\n hours = 0,\n minutes = 0,\n seconds = 0,\n milliseconds = 0,\n } = duration\n\n // Check ranges\n if (years < 0) {\n console.error(`Range error years must be greater than 0: received ${years}`)\n return new Date(date)\n }\n if (months < 0 || months > 11) {\n console.error(`Range error month must be 0 <= month <= 11: received ${months}`)\n return new Date(date)\n }\n if (days < 0) {\n console.error(`Range error days must be greater than 0: received ${days}`)\n return new Date(date)\n }\n if (hours < 0 || hours > 23) {\n console.error(`Range error hours must be 0 <= hours <= 23: received ${hours}`)\n return new Date(date)\n }\n if (minutes < 0 || minutes > 59) {\n console.error(`Range error minutes must be 0 <= minutes <= 59: received ${minutes}`)\n return new Date(date)\n }\n if (seconds < 0 || seconds > 59) {\n console.error(`Range error seconds must be 0 <= seconds <= 59: received ${seconds}`)\n return new Date(date)\n }\n if (milliseconds < 0) {\n console.error(`Range error seconds must be greater than 0: received ${milliseconds}`)\n return new Date(date)\n }\n\n const multiplier = isAdding ? 1 : -1\n\n const newDate = new Date(date)\n\n newDate.setFullYear(newDate.getFullYear() + multiplier * years)\n\n newDate.setMonth(newDate.getMonth() + multiplier * months)\n\n newDate.setDate(newDate.getDate() + multiplier * days)\n\n newDate.setHours(newDate.getHours() + multiplier * hours)\n\n newDate.setMinutes(newDate.getMinutes() + multiplier * minutes)\n\n newDate.setSeconds(newDate.getSeconds() + multiplier * seconds)\n\n newDate.setMilliseconds(newDate.getMilliseconds() + multiplier * milliseconds)\n\n return newDate\n}\n\nexport const addDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, true)\n}\n\nexport const subtractDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, false)\n}\n\nexport const getBetweenDuration = (startDate: Date, endDate: Date): Duration => {\n const durationInMilliseconds = endDate.getTime() - startDate.getTime()\n\n const millisecondsInSecond = 1000\n const millisecondsInMinute = 60 * millisecondsInSecond\n const millisecondsInHour = 60 * millisecondsInMinute\n const millisecondsInDay = 24 * millisecondsInHour\n const millisecondsInMonth = 30 * millisecondsInDay // Rough estimation, can be adjusted\n\n const years = Math.floor(durationInMilliseconds / (365.25 * millisecondsInDay))\n const months = Math.floor(durationInMilliseconds / millisecondsInMonth)\n const days = Math.floor(durationInMilliseconds / millisecondsInDay)\n const hours = Math.floor((durationInMilliseconds % millisecondsInDay) / millisecondsInHour)\n const seconds = Math.floor((durationInMilliseconds % millisecondsInHour) / millisecondsInSecond)\n const milliseconds = durationInMilliseconds % millisecondsInSecond\n\n return {\n years,\n months,\n days,\n hours,\n seconds,\n milliseconds,\n }\n}\n\n/** Checks if a given date is in the range of two dates\n *\n * An undefined value for startDate or endDate means no bound for the start or end respectively\n */\nexport const isInTimeSpan = (value: Date, startDate?: Date, endDate?: Date): boolean => {\n if(startDate && endDate) {\n console.assert(startDate <= endDate)\n return startDate <= value && value <= endDate\n } else if (startDate) {\n return startDate <= value\n } else if(endDate) {\n return endDate >= value\n } else {\n return true\n }\n}\n\n/** Compare two dates on the year, month, day */\nexport const equalDate = (date1: Date, date2: Date) => {\n return date1.getFullYear() === date2.getFullYear()\n && date1.getMonth() === date2.getMonth()\n && date1.getDate() === date2.getDate()\n}\n\nexport const getWeeksForCalenderMonth = (date: Date, weekStart: WeekDay, weeks: number = 6) => {\n const month = date.getMonth()\n const year = date.getFullYear()\n\n const dayList: Date[] = []\n let currentDate = new Date(year, month, 1) // Start of month\n const weekStartIndex = weekDayList.indexOf(weekStart)\n\n // Move the current day to the week before\n while (currentDate.getDay() !== weekStartIndex) {\n currentDate = subtractDuration(currentDate, { days: 1 })\n }\n\n while (dayList.length < 7 * weeks) {\n const date = new Date(currentDate)\n date.setHours(date.getHours(), date.getMinutes()) // To make sure we are not overwriting the time\n dayList.push(date)\n currentDate = addDuration(currentDate, { days: 1 })\n }\n\n // weeks\n return equalSizeGroups(dayList, 7)\n}\n","import type { PropsWithChildren, ButtonHTMLAttributes, ReactNode } from 'react'\nimport clsx from 'clsx'\n\nexport type SolidButtonColor = 'primary' | 'secondary' | 'tertiary' | 'positive' | 'warning'| 'negative'\nexport type OutlineButtonColor = 'primary'\nexport type TextButtonColor = 'negative' | 'neutral'\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\nexport const ButtonSizePaddings: Record<ButtonSizes, string> = {\n small: 'btn-sm',\n medium: 'btn-md',\n large: 'btn-lg'\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\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 }[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 }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n className,\n {\n 'text-disabled-text bg-disabled-background': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonSizePaddings[size]\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 className, {\n 'text-disabled-text border-disabled-outline)': disabled,\n [clsx(colorClasses, 'hover:brightness-80')]: !disabled,\n },\n ButtonSizePaddings[size]\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 negative: 'bg-transparent text-button-text-negative-text',\n neutral: 'bg-transparent text-button-text-neutral-text',\n }[color]\n\n const iconColorClasses = {\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 className, {\n 'text-disabled-text': disabled,\n [clsx(colorClasses, 'hover:bg-button-text-hover-background rounded-full')]: !disabled,\n },\n ButtonSizePaddings[size]\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// TODO Icon button\n\nexport { SolidButton, OutlineButton, TextButton }\n","import { useEffect, useRef, useState } from 'react'\nimport { Scrollbars } from 'react-custom-scrollbars-2'\nimport { noop } from '../../util/noop'\nimport { equalSizeGroups, range } from '../../util/array'\nimport clsx from 'clsx'\nimport { Expandable } from '../Expandable'\nimport { addDuration, monthsList, subtractDuration } from '../../util/date'\nimport { useLocale } from '../../hooks/useLanguage'\n\nexport type YearMonthPickerProps = {\n displayedYearMonth?: Date,\n start?: Date,\n end?: Date,\n onChange?: (date: Date) => void,\n className?: string,\n maxHeight?: number,\n showValueOpen?: boolean,\n}\n\n// TODO use a dynamically loading infinite list here\nexport const YearMonthPicker = ({\n displayedYearMonth = new Date(),\n start = subtractDuration(new Date(), { years: 50 }),\n end = addDuration(new Date(), { years: 50 }),\n onChange = noop,\n className = '',\n maxHeight = 300,\n showValueOpen = true\n }: YearMonthPickerProps) => {\n const locale = useLocale()\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const scrollToItem = () => {\n if (ref.current) {\n ref.current.scrollIntoView({\n behavior: 'instant',\n block: 'center',\n })\n }\n }\n\n scrollToItem()\n }, [ref])\n\n if (end < start) {\n console.error(`startYear: (${start}) less than endYear: (${end})`)\n return null\n }\n\n const years = range(start.getFullYear(), end.getFullYear())\n\n return (\n <div className={clsx('col select-none', className)}>\n <Scrollbars autoHeight autoHeightMax={maxHeight} style={{ height: '100%' }}>\n <div className=\"col gap-y-1 mr-3\">\n {years.map(year => {\n const selectedYear = displayedYearMonth.getFullYear() === year\n return (\n <Expandable\n key={year}\n ref={(displayedYearMonth.getFullYear() ?? new Date().getFullYear()) === year ? ref : undefined}\n label={<span className={clsx({ 'text-primary font-bold': selectedYear })}>{year}</span>}\n initialExpansion={showValueOpen && selectedYear}\n >\n <div className=\"col gap-y-1 px-2 pb-2\">\n {equalSizeGroups([...monthsList], 3).map((monthList, index) => (\n <div key={index} className=\"row\">\n {monthList.map(month => {\n const monthIndex = monthsList.indexOf(month)\n const newDate = new Date(year, monthIndex)\n\n const selectedMonth = selectedYear && monthIndex === displayedYearMonth.getMonth()\n const firstOfMonth = new Date(year, monthIndex, 1)\n const lastOfMonth = new Date(year, monthIndex, 1)\n const isAfterStart = start === undefined || start <= addDuration(subtractDuration(lastOfMonth, { days: 1 }), { months: 1 })\n const isBeforeEnd = end === undefined || firstOfMonth <= end\n const isValid = isAfterStart && isBeforeEnd\n return (\n <button\n key={month}\n disabled={!isValid}\n className={clsx(\n 'chip hover:brightness-95 flex-1',\n {\n 'bg-gray-50 text-black': !selectedMonth && isValid,\n 'bg-primary text-on-primary': selectedMonth && isValid,\n 'bg-disabled-background text-disabled-text': !isValid\n }\n )}\n onClick={() => {\n onChange(newDate)\n }}\n >\n {new Intl.DateTimeFormat(locale, { month: 'short' }).format(newDate)}\n </button>\n )\n })}\n </div>\n ))}\n </div>\n </Expandable>\n )\n })}\n </div>\n </Scrollbars>\n </div>\n )\n}\n\nexport const ControlledYearMonthPicker = ({\n displayedYearMonth = new Date(),\n onChange = noop,\n ...props\n }: YearMonthPickerProps) => {\n const [yearMonth, setYearMonth] = useState<Date>(displayedYearMonth)\n\n useEffect(() => setYearMonth(displayedYearMonth), [displayedYearMonth])\n\n return (\n <YearMonthPicker\n displayedYearMonth={yearMonth}\n onChange={date => {\n setYearMonth(date)\n onChange(date)\n }}\n {...props}\n />\n )\n}\n","import type { PropsWithChildren, ReactNode } from 'react'\nimport { forwardRef, useState } from 'react'\nimport { ChevronDown, ChevronUp } from 'lucide-react'\nimport clsx from 'clsx'\n\ntype IconBuilder = (expanded: boolean) => ReactNode\n\nexport type ExpandableProps = PropsWithChildren<{\n label: ReactNode,\n icon?: IconBuilder,\n initialExpansion?: boolean,\n /**\n * Whether the expansion should only happen when the header is clicked or on the entire component\n */\n clickOnlyOnHeader?: boolean,\n className?: string,\n headerClassName?: string,\n}>\n\nconst DefaultIcon: IconBuilder = (expanded) => expanded ?\n (<ChevronUp size={16} className=\"min-w-[16px]\"/>)\n : (<ChevronDown size={16} className=\"min-w-[16px]\"/>)\n\n/**\n * A Component for showing and hiding content\n */\nexport const Expandable = forwardRef<HTMLDivElement, ExpandableProps>(({\n children,\n label,\n icon,\n initialExpansion = false,\n clickOnlyOnHeader = true,\n className = '',\n headerClassName = ''\n }, ref) => {\n const [isExpanded, setIsExpanded] = useState(initialExpansion)\n icon ??= DefaultIcon\n\n return (\n <div\n ref={ref}\n className={clsx('col bg-surface text-on-surface group rounded-lg shadow-sm', { 'cursor-pointer': !clickOnlyOnHeader }, className)}\n onClick={() => !clickOnlyOnHeader && setIsExpanded(!isExpanded)}\n >\n <button\n className={clsx('btn-md rounded-lg justify-between items-center bg-surface text-on-surface', { 'group-hover:brightness-95': !isExpanded }, headerClassName)}\n onClick={() => clickOnlyOnHeader && setIsExpanded(!isExpanded)}\n >\n {label}\n {icon(isExpanded)}\n </button>\n {isExpanded && (\n <div className=\"col\">\n {children}\n </div>\n )}\n </div>\n )\n})\n\nExpandable.displayName = 'Expandable'\n","import type { WeekDay } from '../../util/date'\nimport { isInTimeSpan } from '../../util/date'\nimport { equalDate, getWeeksForCalenderMonth } from '../../util/date'\nimport { noop } from '../../util/noop'\nimport clsx from 'clsx'\nimport { useLocale } from '../../hooks/useLanguage'\nimport { useEffect, useState } from 'react'\n\nexport type DayPickerProps = {\n displayedMonth: Date,\n selected?: Date,\n start?: Date,\n end?: Date,\n onChange?: (date: Date) => void,\n weekStart?: WeekDay,\n markToday?: boolean,\n className?: string,\n}\n\n/**\n * A component for selecting a day of a month\n */\nexport const DayPicker = ({\n displayedMonth,\n selected,\n start,\n end,\n onChange = noop,\n weekStart = 'monday',\n markToday = true,\n className = ''\n }: DayPickerProps) => {\n const locale = useLocale()\n const month = displayedMonth.getMonth()\n const weeks = getWeeksForCalenderMonth(displayedMonth, weekStart)\n\n return (\n <div className={clsx('col gap-y-1 min-w-[220px] select-none', className)}>\n <div className=\"row text-center\">\n {weeks[0]!.map((weekDay, index) => (\n <div key={index} className=\"flex-1 font-semibold\">\n {new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(weekDay).substring(0, 2)}\n </div>\n ))}\n </div>\n {weeks.map((week, index) => (\n <div key={index} className=\"row text-center\">\n {week.map((date) => {\n const isSelected = !!selected && equalDate(selected, date)\n const isToday = equalDate(new Date(), date)\n const isSameMonth = date.getMonth() === month\n const isDayValid = isInTimeSpan(date, start, end)\n return (\n <button\n disabled={!isDayValid}\n key={date.getDate()}\n className={clsx(\n 'flex-1 rounded-full border-2 border-transparent shadow-sm',\n {\n 'text-gray-700 bg-gray-100': !isSameMonth && isDayValid,\n 'text-black bg-white': !isSelected && isSameMonth && isDayValid,\n 'text-on-primary bg-primary': isSelected,\n 'border-black': isToday && markToday,\n 'hover:brightness-90 hover:bg-primary hover:text-on-primary': isDayValid,\n 'text-disabled-text bg-disabled-background': !isDayValid\n }\n )}\n onClick={() => onChange(date)}\n >\n {date.getDate()}\n </button>\n )\n })}\n </div>\n ))}\n </div>\n )\n}\n\nexport const DayPickerControlled = ({ displayedMonth, onChange = noop, ...restProps }: DayPickerProps) => {\n const [date, setDate] = useState(displayedMonth)\n\n useEffect(() => setDate(displayedMonth), [displayedMonth])\n\n return (\n <DayPicker\n displayedMonth={date}\n onChange={newDate => {\n setDate(newDate)\n onChange(newDate)\n }}\n {...restProps}\n />\n )\n}\n"],"mappings":"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