@helpwave/hightide 0.1.22 → 0.1.23

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 (102) hide show
  1. package/README.md +5 -0
  2. package/dist/components/branding/HelpwaveBadge.js +8 -5
  3. package/dist/components/branding/HelpwaveBadge.js.map +1 -1
  4. package/dist/components/branding/HelpwaveBadge.mjs +8 -5
  5. package/dist/components/branding/HelpwaveBadge.mjs.map +1 -1
  6. package/dist/components/icons-and-geometry/Avatar.js +2912 -33
  7. package/dist/components/icons-and-geometry/Avatar.js.map +1 -1
  8. package/dist/components/icons-and-geometry/Avatar.mjs +2941 -33
  9. package/dist/components/icons-and-geometry/Avatar.mjs.map +1 -1
  10. package/dist/components/icons-and-geometry/Tag.js +2912 -1
  11. package/dist/components/icons-and-geometry/Tag.js.map +1 -1
  12. package/dist/components/icons-and-geometry/Tag.mjs +2931 -1
  13. package/dist/components/icons-and-geometry/Tag.mjs.map +1 -1
  14. package/dist/components/layout-and-navigation/BreadCrumb.d.mts +2 -1
  15. package/dist/components/layout-and-navigation/BreadCrumb.d.ts +2 -1
  16. package/dist/components/layout-and-navigation/BreadCrumb.js +15 -11
  17. package/dist/components/layout-and-navigation/BreadCrumb.js.map +1 -1
  18. package/dist/components/layout-and-navigation/BreadCrumb.mjs +15 -11
  19. package/dist/components/layout-and-navigation/BreadCrumb.mjs.map +1 -1
  20. package/dist/components/layout-and-navigation/Chip.js +2 -2
  21. package/dist/components/layout-and-navigation/Chip.js.map +1 -1
  22. package/dist/components/layout-and-navigation/Chip.mjs +2 -2
  23. package/dist/components/layout-and-navigation/Chip.mjs.map +1 -1
  24. package/dist/components/layout-and-navigation/Tile.d.mts +9 -10
  25. package/dist/components/layout-and-navigation/Tile.d.ts +9 -10
  26. package/dist/components/layout-and-navigation/Tile.js +21 -4
  27. package/dist/components/layout-and-navigation/Tile.js.map +1 -1
  28. package/dist/components/layout-and-navigation/Tile.mjs +20 -4
  29. package/dist/components/layout-and-navigation/Tile.mjs.map +1 -1
  30. package/dist/components/loading-states/LoadingAndErrorComponent.js +1 -1
  31. package/dist/components/loading-states/LoadingAndErrorComponent.js.map +1 -1
  32. package/dist/components/loading-states/LoadingAndErrorComponent.mjs +1 -1
  33. package/dist/components/loading-states/LoadingAndErrorComponent.mjs.map +1 -1
  34. package/dist/components/modals/LanguageModal.js +21 -22
  35. package/dist/components/modals/LanguageModal.js.map +1 -1
  36. package/dist/components/modals/LanguageModal.mjs +21 -22
  37. package/dist/components/modals/LanguageModal.mjs.map +1 -1
  38. package/dist/components/modals/ThemeModal.js +21 -22
  39. package/dist/components/modals/ThemeModal.js.map +1 -1
  40. package/dist/components/modals/ThemeModal.mjs +21 -22
  41. package/dist/components/modals/ThemeModal.mjs.map +1 -1
  42. package/dist/components/properties/CheckboxProperty.js +1 -1
  43. package/dist/components/properties/CheckboxProperty.js.map +1 -1
  44. package/dist/components/properties/CheckboxProperty.mjs +1 -1
  45. package/dist/components/properties/CheckboxProperty.mjs.map +1 -1
  46. package/dist/components/properties/DateProperty.js +1 -1
  47. package/dist/components/properties/DateProperty.js.map +1 -1
  48. package/dist/components/properties/DateProperty.mjs +1 -1
  49. package/dist/components/properties/DateProperty.mjs.map +1 -1
  50. package/dist/components/properties/MultiSelectProperty.d.mts +0 -1
  51. package/dist/components/properties/MultiSelectProperty.d.ts +0 -1
  52. package/dist/components/properties/MultiSelectProperty.js +745 -740
  53. package/dist/components/properties/MultiSelectProperty.js.map +1 -1
  54. package/dist/components/properties/MultiSelectProperty.mjs +752 -747
  55. package/dist/components/properties/MultiSelectProperty.mjs.map +1 -1
  56. package/dist/components/properties/NumberProperty.js +1 -1
  57. package/dist/components/properties/NumberProperty.js.map +1 -1
  58. package/dist/components/properties/NumberProperty.mjs +1 -1
  59. package/dist/components/properties/NumberProperty.mjs.map +1 -1
  60. package/dist/components/properties/PropertyBase.js +1 -1
  61. package/dist/components/properties/PropertyBase.js.map +1 -1
  62. package/dist/components/properties/PropertyBase.mjs +1 -1
  63. package/dist/components/properties/PropertyBase.mjs.map +1 -1
  64. package/dist/components/properties/SelectProperty.d.mts +0 -1
  65. package/dist/components/properties/SelectProperty.d.ts +0 -1
  66. package/dist/components/properties/SelectProperty.js +24 -25
  67. package/dist/components/properties/SelectProperty.js.map +1 -1
  68. package/dist/components/properties/SelectProperty.mjs +24 -25
  69. package/dist/components/properties/SelectProperty.mjs.map +1 -1
  70. package/dist/components/properties/TextProperty.js +1 -1
  71. package/dist/components/properties/TextProperty.js.map +1 -1
  72. package/dist/components/properties/TextProperty.mjs +1 -1
  73. package/dist/components/properties/TextProperty.mjs.map +1 -1
  74. package/dist/components/user-action/MultiSelect.d.mts +0 -1
  75. package/dist/components/user-action/MultiSelect.d.ts +0 -1
  76. package/dist/components/user-action/MultiSelect.js +617 -612
  77. package/dist/components/user-action/MultiSelect.js.map +1 -1
  78. package/dist/components/user-action/MultiSelect.mjs +635 -630
  79. package/dist/components/user-action/MultiSelect.mjs.map +1 -1
  80. package/dist/components/user-action/ScrollPicker.js +1 -1
  81. package/dist/components/user-action/ScrollPicker.js.map +1 -1
  82. package/dist/components/user-action/ScrollPicker.mjs +1 -1
  83. package/dist/components/user-action/ScrollPicker.mjs.map +1 -1
  84. package/dist/components/user-action/Select.d.mts +1 -4
  85. package/dist/components/user-action/Select.d.ts +1 -4
  86. package/dist/components/user-action/Select.js +21 -24
  87. package/dist/components/user-action/Select.js.map +1 -1
  88. package/dist/components/user-action/Select.mjs +21 -23
  89. package/dist/components/user-action/Select.mjs.map +1 -1
  90. package/dist/css/globals.css +175 -179
  91. package/dist/css/uncompiled/globals.css +3 -3
  92. package/dist/css/uncompiled/textstyles.css +5 -5
  93. package/dist/css/uncompiled/theme/colors-basic.css +13 -5
  94. package/dist/css/uncompiled/theme/colors-component.css +56 -41
  95. package/dist/css/uncompiled/theme/colors-semantic.css +76 -83
  96. package/dist/index.d.mts +2 -2
  97. package/dist/index.d.ts +2 -2
  98. package/dist/index.js +3158 -371
  99. package/dist/index.js.map +1 -1
  100. package/dist/index.mjs +3030 -243
  101. package/dist/index.mjs.map +1 -1
  102. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/user-action/ScrollPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/util/math.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\nimport { getNeighbours, range } from '../../util/array'\nimport { clamp } from '../../util/math'\n\nexport type ScrollPickerProps<T> = {\n options: T[],\n mapping: (value: T) => string,\n selected?: T,\n onChange?: (value: T) => void,\n disabled?: boolean,\n}\n\ntype AnimationData<T> = {\n /** The index we scroll to */\n targetIndex: number,\n /** The index we are currently showing centered */\n currentIndex: number,\n items: T[],\n /** From -0.5 to 0.5 */\n transition: number,\n velocity: number,\n animationVelocity: number,\n lastTimeStamp?: number,\n lastScrollTimeStamp?: number,\n}\n\nconst up = 1\nconst down = -1\ntype Direction = 1 | -1\n\n/**\n * A component for picking an option by scrolling\n */\nexport const ScrollPicker = <T, >({\n options,\n mapping,\n selected,\n onChange = noop,\n disabled = false,\n }: ScrollPickerProps<T>) => {\n let selectedIndex = 0\n if (selected && options.indexOf(selected) !== -1) {\n selectedIndex = options.indexOf(selected)\n }\n const [{\n currentIndex,\n transition,\n items,\n lastTimeStamp\n }, setAnimation] = useState<AnimationData<T>>({\n targetIndex: selectedIndex,\n currentIndex: disabled ? selectedIndex : 0,\n velocity: 0,\n animationVelocity: Math.floor(options.length / 2),\n transition: 0,\n items: options,\n })\n\n const itemsShownCount = 5\n const shownItems = getNeighbours(range(items.length), currentIndex).map(index => ({\n name: mapping(items[index]!), index\n }))\n\n const itemHeight = 40\n const distance = 8\n\n const containerHeight = itemHeight * (itemsShownCount - 2) + distance * (itemsShownCount - 2 + 1)\n\n const getDirection = useCallback((targetIndex: number, currentIndex: number, transition: number, length: number): Direction => {\n if (targetIndex === currentIndex) {\n return transition > 0 ? up : down\n }\n let distanceForward = targetIndex - currentIndex\n if (distanceForward < 0) {\n distanceForward += length\n }\n return distanceForward >= length / 2 ? down : up\n }, [])\n\n const animate = useCallback((timestamp: number, startTime: number | undefined) => {\n setAnimation((prevState) => {\n const {\n targetIndex,\n currentIndex,\n transition,\n animationVelocity,\n velocity,\n items,\n lastScrollTimeStamp\n } = prevState\n if (disabled) {\n return { ...prevState, currentIndex: targetIndex, velocity: 0, lastTimeStamp: timestamp }\n }\n if ((targetIndex === currentIndex && velocity === 0 && transition === 0) || !startTime) {\n return { ...prevState, lastTimeStamp: timestamp }\n }\n const progress = (timestamp - startTime) / 1000 // to seconds\n const direction = getDirection(targetIndex, currentIndex, transition, items.length)\n\n let newVelocity = velocity\n let usedVelocity\n let newCurrentIndex = currentIndex\n const isAutoScrolling = velocity === 0 && (!lastScrollTimeStamp || timestamp - lastScrollTimeStamp > 300)\n\n const newLastScrollTimeStamp = velocity !== 0 ? timestamp : lastScrollTimeStamp\n\n // manual scrolling\n if (isAutoScrolling) {\n usedVelocity = direction * animationVelocity\n } else {\n usedVelocity = velocity\n newVelocity = velocity * 0.5 // drag loss\n if (Math.abs(newVelocity) <= 0.05) {\n newVelocity = 0\n }\n }\n\n let newTransition = transition + usedVelocity * progress\n const changeThreshold = 0.5\n\n while (newTransition >= changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition >= changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = (currentIndex + 1) % items.length\n newTransition -= 1\n }\n if (newTransition >= changeThreshold) {\n newTransition = 0\n }\n while (newTransition <= -changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition <= -changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1\n newTransition += 1\n }\n let newTargetIndex = targetIndex\n if (!isAutoScrolling) {\n newTargetIndex = newCurrentIndex\n }\n\n if ((currentIndex !== newTargetIndex || newTargetIndex !== targetIndex) && newTargetIndex === newCurrentIndex) {\n onChange(items[newCurrentIndex]!)\n }\n return {\n targetIndex: newTargetIndex,\n currentIndex: newCurrentIndex,\n animationVelocity,\n transition: newTransition,\n velocity: newVelocity,\n items,\n lastTimeStamp: timestamp,\n lastScrollTimeStamp: newLastScrollTimeStamp\n }\n })\n }, [disabled, getDirection, onChange])\n\n useEffect(() => {\n // constant update\n requestAnimationFrame((timestamp) => animate(timestamp, lastTimeStamp))\n })\n\n const opacity = (transition: number, index: number, itemsCount: number) => {\n const max = 100\n const min = 0\n const distance = max - min\n\n let opacityValue = min\n const unitTransition = clamp((transition) / 0.5)\n if (index === 1 || index === itemsCount - 2) {\n if (index === 1 && transition > 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n if (index === itemsCount - 2 && transition < 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n } else {\n opacityValue = max\n }\n\n // TODO this is not the right value for the bottom entry\n return clamp(1 - (opacityValue / max))\n }\n\n return (\n <div\n className=\"relative overflow-hidden\"\n style={{ height: containerHeight }}\n onWheel={event => {\n if (event.deltaY !== 0) {\n // TODO slower increase\n setAnimation(({ velocity, ...animationData }) =>\n ({ ...animationData, velocity: velocity + event.deltaY }))\n }\n }}\n >\n <div className=\"absolute top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2\">\n <div\n className=\"absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/30 border-y-2 border-x-0 \"\n style={{ height: `${itemHeight}px` }}\n />\n <div\n className=\"flex-col-2 select-none\"\n style={{\n transform: `translateY(${-transition * (distance + itemHeight)}px)`,\n columnGap: `${distance}px`,\n }}\n >\n {shownItems.map(({ name, index }, arrayIndex) => (\n <div\n key={index}\n className={clsx(\n `flex-col-2 items-center justify-center rounded-md`,\n {\n 'text-primary font-bold': currentIndex === index,\n 'text-on-background': currentIndex === index,\n 'cursor-pointer': !disabled,\n 'cursor-not-allowed': disabled,\n }\n )}\n style={{\n opacity: currentIndex !== index ? opacity(transition, arrayIndex, shownItems.length) : undefined,\n height: `${itemHeight}px`,\n maxHeight: `${itemHeight}px`,\n }}\n onClick={() => !disabled && setAnimation(prevState => ({ ...prevState, targetIndex: index }))}\n >\n {name}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\nexport type RangeOptions = {\n /** Whether the range can be defined empty via end < start without a warning */\n allowEmptyRange: boolean,\n stepSize: number,\n exclusiveStart: boolean,\n exclusiveEnd: boolean,\n}\n\nconst defaultRangeOptions: RangeOptions = {\n allowEmptyRange: false,\n stepSize: 1,\n exclusiveStart: false,\n exclusiveEnd: true,\n}\n\n/**\n * @param endOrRange The end value or a range [start, end], end is exclusive\n * @param options the options for defining the range\n */\nexport const range = (endOrRange: number | [number, number], options?: Partial<RangeOptions>): number[] => {\n const { allowEmptyRange, stepSize, exclusiveStart, exclusiveEnd } = { ...defaultRangeOptions, ...options }\n let start = 0\n let end: number\n if (typeof endOrRange === 'number') {\n end = endOrRange\n } else {\n start = endOrRange[0]\n end = endOrRange[1]\n }\n if (!exclusiveEnd) {\n end -= 1\n }\n if (exclusiveStart) {\n start += 1\n }\n\n if (end - 1 < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set options.allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start }, (_, index) => index * stepSize + 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","export const clamp = (value: number, min: number = 0, max: number = 1): number => {\n return Math.min(Math.max(value, min), max)\n}\n"],"mappings":"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","names":["currentIndex","transition","items","distance","clsx"]}
1
+ {"version":3,"sources":["../../../src/components/user-action/ScrollPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/util/math.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\nimport { getNeighbours, range } from '../../util/array'\nimport { clamp } from '../../util/math'\n\nexport type ScrollPickerProps<T> = {\n options: T[],\n mapping: (value: T) => string,\n selected?: T,\n onChange?: (value: T) => void,\n disabled?: boolean,\n}\n\ntype AnimationData<T> = {\n /** The index we scroll to */\n targetIndex: number,\n /** The index we are currently showing centered */\n currentIndex: number,\n items: T[],\n /** From -0.5 to 0.5 */\n transition: number,\n velocity: number,\n animationVelocity: number,\n lastTimeStamp?: number,\n lastScrollTimeStamp?: number,\n}\n\nconst up = 1\nconst down = -1\ntype Direction = 1 | -1\n\n/**\n * A component for picking an option by scrolling\n */\nexport const ScrollPicker = <T, >({\n options,\n mapping,\n selected,\n onChange = noop,\n disabled = false,\n }: ScrollPickerProps<T>) => {\n let selectedIndex = 0\n if (selected && options.indexOf(selected) !== -1) {\n selectedIndex = options.indexOf(selected)\n }\n const [{\n currentIndex,\n transition,\n items,\n lastTimeStamp\n }, setAnimation] = useState<AnimationData<T>>({\n targetIndex: selectedIndex,\n currentIndex: disabled ? selectedIndex : 0,\n velocity: 0,\n animationVelocity: Math.floor(options.length / 2),\n transition: 0,\n items: options,\n })\n\n const itemsShownCount = 5\n const shownItems = getNeighbours(range(items.length), currentIndex).map(index => ({\n name: mapping(items[index]!), index\n }))\n\n const itemHeight = 40\n const distance = 8\n\n const containerHeight = itemHeight * (itemsShownCount - 2) + distance * (itemsShownCount - 2 + 1)\n\n const getDirection = useCallback((targetIndex: number, currentIndex: number, transition: number, length: number): Direction => {\n if (targetIndex === currentIndex) {\n return transition > 0 ? up : down\n }\n let distanceForward = targetIndex - currentIndex\n if (distanceForward < 0) {\n distanceForward += length\n }\n return distanceForward >= length / 2 ? down : up\n }, [])\n\n const animate = useCallback((timestamp: number, startTime: number | undefined) => {\n setAnimation((prevState) => {\n const {\n targetIndex,\n currentIndex,\n transition,\n animationVelocity,\n velocity,\n items,\n lastScrollTimeStamp\n } = prevState\n if (disabled) {\n return { ...prevState, currentIndex: targetIndex, velocity: 0, lastTimeStamp: timestamp }\n }\n if ((targetIndex === currentIndex && velocity === 0 && transition === 0) || !startTime) {\n return { ...prevState, lastTimeStamp: timestamp }\n }\n const progress = (timestamp - startTime) / 1000 // to seconds\n const direction = getDirection(targetIndex, currentIndex, transition, items.length)\n\n let newVelocity = velocity\n let usedVelocity\n let newCurrentIndex = currentIndex\n const isAutoScrolling = velocity === 0 && (!lastScrollTimeStamp || timestamp - lastScrollTimeStamp > 300)\n\n const newLastScrollTimeStamp = velocity !== 0 ? timestamp : lastScrollTimeStamp\n\n // manual scrolling\n if (isAutoScrolling) {\n usedVelocity = direction * animationVelocity\n } else {\n usedVelocity = velocity\n newVelocity = velocity * 0.5 // drag loss\n if (Math.abs(newVelocity) <= 0.05) {\n newVelocity = 0\n }\n }\n\n let newTransition = transition + usedVelocity * progress\n const changeThreshold = 0.5\n\n while (newTransition >= changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition >= changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = (currentIndex + 1) % items.length\n newTransition -= 1\n }\n if (newTransition >= changeThreshold) {\n newTransition = 0\n }\n while (newTransition <= -changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition <= -changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1\n newTransition += 1\n }\n let newTargetIndex = targetIndex\n if (!isAutoScrolling) {\n newTargetIndex = newCurrentIndex\n }\n\n if ((currentIndex !== newTargetIndex || newTargetIndex !== targetIndex) && newTargetIndex === newCurrentIndex) {\n onChange(items[newCurrentIndex]!)\n }\n return {\n targetIndex: newTargetIndex,\n currentIndex: newCurrentIndex,\n animationVelocity,\n transition: newTransition,\n velocity: newVelocity,\n items,\n lastTimeStamp: timestamp,\n lastScrollTimeStamp: newLastScrollTimeStamp\n }\n })\n }, [disabled, getDirection, onChange])\n\n useEffect(() => {\n // constant update\n requestAnimationFrame((timestamp) => animate(timestamp, lastTimeStamp))\n })\n\n const opacity = (transition: number, index: number, itemsCount: number) => {\n const max = 100\n const min = 0\n const distance = max - min\n\n let opacityValue = min\n const unitTransition = clamp((transition) / 0.5)\n if (index === 1 || index === itemsCount - 2) {\n if (index === 1 && transition > 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n if (index === itemsCount - 2 && transition < 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n } else {\n opacityValue = max\n }\n\n // TODO this is not the right value for the bottom entry\n return clamp(1 - (opacityValue / max))\n }\n\n return (\n <div\n className=\"relative overflow-hidden\"\n style={{ height: containerHeight }}\n onWheel={event => {\n if (event.deltaY !== 0) {\n // TODO slower increase\n setAnimation(({ velocity, ...animationData }) =>\n ({ ...animationData, velocity: velocity + event.deltaY }))\n }\n }}\n >\n <div className=\"absolute top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2\">\n <div\n className=\"absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/50 border-y-2 border-x-0 \"\n style={{ height: `${itemHeight}px` }}\n />\n <div\n className=\"flex-col-2 select-none\"\n style={{\n transform: `translateY(${-transition * (distance + itemHeight)}px)`,\n columnGap: `${distance}px`,\n }}\n >\n {shownItems.map(({ name, index }, arrayIndex) => (\n <div\n key={index}\n className={clsx(\n `flex-col-2 items-center justify-center rounded-md`,\n {\n 'text-primary font-bold': currentIndex === index,\n 'text-on-background': currentIndex === index,\n 'cursor-pointer': !disabled,\n 'cursor-not-allowed': disabled,\n }\n )}\n style={{\n opacity: currentIndex !== index ? opacity(transition, arrayIndex, shownItems.length) : undefined,\n height: `${itemHeight}px`,\n maxHeight: `${itemHeight}px`,\n }}\n onClick={() => !disabled && setAnimation(prevState => ({ ...prevState, targetIndex: index }))}\n >\n {name}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\nexport type RangeOptions = {\n /** Whether the range can be defined empty via end < start without a warning */\n allowEmptyRange: boolean,\n stepSize: number,\n exclusiveStart: boolean,\n exclusiveEnd: boolean,\n}\n\nconst defaultRangeOptions: RangeOptions = {\n allowEmptyRange: false,\n stepSize: 1,\n exclusiveStart: false,\n exclusiveEnd: true,\n}\n\n/**\n * @param endOrRange The end value or a range [start, end], end is exclusive\n * @param options the options for defining the range\n */\nexport const range = (endOrRange: number | [number, number], options?: Partial<RangeOptions>): number[] => {\n const { allowEmptyRange, stepSize, exclusiveStart, exclusiveEnd } = { ...defaultRangeOptions, ...options }\n let start = 0\n let end: number\n if (typeof endOrRange === 'number') {\n end = endOrRange\n } else {\n start = endOrRange[0]\n end = endOrRange[1]\n }\n if (!exclusiveEnd) {\n end -= 1\n }\n if (exclusiveStart) {\n start += 1\n }\n\n if (end - 1 < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set options.allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start }, (_, index) => index * stepSize + 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","export const clamp = (value: number, min: number = 0, max: number = 1): number => {\n return Math.min(Math.max(value, min), max)\n}\n"],"mappings":"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","names":["currentIndex","transition","items","distance","clsx"]}
@@ -222,7 +222,7 @@ var ScrollPicker = ({
222
222
  /* @__PURE__ */ jsx(
223
223
  "div",
224
224
  {
225
- className: "absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/30 border-y-2 border-x-0 ",
225
+ className: "absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/50 border-y-2 border-x-0 ",
226
226
  style: { height: `${itemHeight}px` }
227
227
  }
228
228
  ),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/user-action/ScrollPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/util/math.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\nimport { getNeighbours, range } from '../../util/array'\nimport { clamp } from '../../util/math'\n\nexport type ScrollPickerProps<T> = {\n options: T[],\n mapping: (value: T) => string,\n selected?: T,\n onChange?: (value: T) => void,\n disabled?: boolean,\n}\n\ntype AnimationData<T> = {\n /** The index we scroll to */\n targetIndex: number,\n /** The index we are currently showing centered */\n currentIndex: number,\n items: T[],\n /** From -0.5 to 0.5 */\n transition: number,\n velocity: number,\n animationVelocity: number,\n lastTimeStamp?: number,\n lastScrollTimeStamp?: number,\n}\n\nconst up = 1\nconst down = -1\ntype Direction = 1 | -1\n\n/**\n * A component for picking an option by scrolling\n */\nexport const ScrollPicker = <T, >({\n options,\n mapping,\n selected,\n onChange = noop,\n disabled = false,\n }: ScrollPickerProps<T>) => {\n let selectedIndex = 0\n if (selected && options.indexOf(selected) !== -1) {\n selectedIndex = options.indexOf(selected)\n }\n const [{\n currentIndex,\n transition,\n items,\n lastTimeStamp\n }, setAnimation] = useState<AnimationData<T>>({\n targetIndex: selectedIndex,\n currentIndex: disabled ? selectedIndex : 0,\n velocity: 0,\n animationVelocity: Math.floor(options.length / 2),\n transition: 0,\n items: options,\n })\n\n const itemsShownCount = 5\n const shownItems = getNeighbours(range(items.length), currentIndex).map(index => ({\n name: mapping(items[index]!), index\n }))\n\n const itemHeight = 40\n const distance = 8\n\n const containerHeight = itemHeight * (itemsShownCount - 2) + distance * (itemsShownCount - 2 + 1)\n\n const getDirection = useCallback((targetIndex: number, currentIndex: number, transition: number, length: number): Direction => {\n if (targetIndex === currentIndex) {\n return transition > 0 ? up : down\n }\n let distanceForward = targetIndex - currentIndex\n if (distanceForward < 0) {\n distanceForward += length\n }\n return distanceForward >= length / 2 ? down : up\n }, [])\n\n const animate = useCallback((timestamp: number, startTime: number | undefined) => {\n setAnimation((prevState) => {\n const {\n targetIndex,\n currentIndex,\n transition,\n animationVelocity,\n velocity,\n items,\n lastScrollTimeStamp\n } = prevState\n if (disabled) {\n return { ...prevState, currentIndex: targetIndex, velocity: 0, lastTimeStamp: timestamp }\n }\n if ((targetIndex === currentIndex && velocity === 0 && transition === 0) || !startTime) {\n return { ...prevState, lastTimeStamp: timestamp }\n }\n const progress = (timestamp - startTime) / 1000 // to seconds\n const direction = getDirection(targetIndex, currentIndex, transition, items.length)\n\n let newVelocity = velocity\n let usedVelocity\n let newCurrentIndex = currentIndex\n const isAutoScrolling = velocity === 0 && (!lastScrollTimeStamp || timestamp - lastScrollTimeStamp > 300)\n\n const newLastScrollTimeStamp = velocity !== 0 ? timestamp : lastScrollTimeStamp\n\n // manual scrolling\n if (isAutoScrolling) {\n usedVelocity = direction * animationVelocity\n } else {\n usedVelocity = velocity\n newVelocity = velocity * 0.5 // drag loss\n if (Math.abs(newVelocity) <= 0.05) {\n newVelocity = 0\n }\n }\n\n let newTransition = transition + usedVelocity * progress\n const changeThreshold = 0.5\n\n while (newTransition >= changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition >= changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = (currentIndex + 1) % items.length\n newTransition -= 1\n }\n if (newTransition >= changeThreshold) {\n newTransition = 0\n }\n while (newTransition <= -changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition <= -changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1\n newTransition += 1\n }\n let newTargetIndex = targetIndex\n if (!isAutoScrolling) {\n newTargetIndex = newCurrentIndex\n }\n\n if ((currentIndex !== newTargetIndex || newTargetIndex !== targetIndex) && newTargetIndex === newCurrentIndex) {\n onChange(items[newCurrentIndex]!)\n }\n return {\n targetIndex: newTargetIndex,\n currentIndex: newCurrentIndex,\n animationVelocity,\n transition: newTransition,\n velocity: newVelocity,\n items,\n lastTimeStamp: timestamp,\n lastScrollTimeStamp: newLastScrollTimeStamp\n }\n })\n }, [disabled, getDirection, onChange])\n\n useEffect(() => {\n // constant update\n requestAnimationFrame((timestamp) => animate(timestamp, lastTimeStamp))\n })\n\n const opacity = (transition: number, index: number, itemsCount: number) => {\n const max = 100\n const min = 0\n const distance = max - min\n\n let opacityValue = min\n const unitTransition = clamp((transition) / 0.5)\n if (index === 1 || index === itemsCount - 2) {\n if (index === 1 && transition > 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n if (index === itemsCount - 2 && transition < 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n } else {\n opacityValue = max\n }\n\n // TODO this is not the right value for the bottom entry\n return clamp(1 - (opacityValue / max))\n }\n\n return (\n <div\n className=\"relative overflow-hidden\"\n style={{ height: containerHeight }}\n onWheel={event => {\n if (event.deltaY !== 0) {\n // TODO slower increase\n setAnimation(({ velocity, ...animationData }) =>\n ({ ...animationData, velocity: velocity + event.deltaY }))\n }\n }}\n >\n <div className=\"absolute top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2\">\n <div\n className=\"absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/30 border-y-2 border-x-0 \"\n style={{ height: `${itemHeight}px` }}\n />\n <div\n className=\"flex-col-2 select-none\"\n style={{\n transform: `translateY(${-transition * (distance + itemHeight)}px)`,\n columnGap: `${distance}px`,\n }}\n >\n {shownItems.map(({ name, index }, arrayIndex) => (\n <div\n key={index}\n className={clsx(\n `flex-col-2 items-center justify-center rounded-md`,\n {\n 'text-primary font-bold': currentIndex === index,\n 'text-on-background': currentIndex === index,\n 'cursor-pointer': !disabled,\n 'cursor-not-allowed': disabled,\n }\n )}\n style={{\n opacity: currentIndex !== index ? opacity(transition, arrayIndex, shownItems.length) : undefined,\n height: `${itemHeight}px`,\n maxHeight: `${itemHeight}px`,\n }}\n onClick={() => !disabled && setAnimation(prevState => ({ ...prevState, targetIndex: index }))}\n >\n {name}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\nexport type RangeOptions = {\n /** Whether the range can be defined empty via end < start without a warning */\n allowEmptyRange: boolean,\n stepSize: number,\n exclusiveStart: boolean,\n exclusiveEnd: boolean,\n}\n\nconst defaultRangeOptions: RangeOptions = {\n allowEmptyRange: false,\n stepSize: 1,\n exclusiveStart: false,\n exclusiveEnd: true,\n}\n\n/**\n * @param endOrRange The end value or a range [start, end], end is exclusive\n * @param options the options for defining the range\n */\nexport const range = (endOrRange: number | [number, number], options?: Partial<RangeOptions>): number[] => {\n const { allowEmptyRange, stepSize, exclusiveStart, exclusiveEnd } = { ...defaultRangeOptions, ...options }\n let start = 0\n let end: number\n if (typeof endOrRange === 'number') {\n end = endOrRange\n } else {\n start = endOrRange[0]\n end = endOrRange[1]\n }\n if (!exclusiveEnd) {\n end -= 1\n }\n if (exclusiveStart) {\n start += 1\n }\n\n if (end - 1 < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set options.allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start }, (_, index) => index * stepSize + 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","export const clamp = (value: number, min: number = 0, max: number = 1): number => {\n return Math.min(Math.max(value, min), max)\n}\n"],"mappings":"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","names":["currentIndex","transition","items","distance"]}
1
+ {"version":3,"sources":["../../../src/components/user-action/ScrollPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/util/math.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\nimport { getNeighbours, range } from '../../util/array'\nimport { clamp } from '../../util/math'\n\nexport type ScrollPickerProps<T> = {\n options: T[],\n mapping: (value: T) => string,\n selected?: T,\n onChange?: (value: T) => void,\n disabled?: boolean,\n}\n\ntype AnimationData<T> = {\n /** The index we scroll to */\n targetIndex: number,\n /** The index we are currently showing centered */\n currentIndex: number,\n items: T[],\n /** From -0.5 to 0.5 */\n transition: number,\n velocity: number,\n animationVelocity: number,\n lastTimeStamp?: number,\n lastScrollTimeStamp?: number,\n}\n\nconst up = 1\nconst down = -1\ntype Direction = 1 | -1\n\n/**\n * A component for picking an option by scrolling\n */\nexport const ScrollPicker = <T, >({\n options,\n mapping,\n selected,\n onChange = noop,\n disabled = false,\n }: ScrollPickerProps<T>) => {\n let selectedIndex = 0\n if (selected && options.indexOf(selected) !== -1) {\n selectedIndex = options.indexOf(selected)\n }\n const [{\n currentIndex,\n transition,\n items,\n lastTimeStamp\n }, setAnimation] = useState<AnimationData<T>>({\n targetIndex: selectedIndex,\n currentIndex: disabled ? selectedIndex : 0,\n velocity: 0,\n animationVelocity: Math.floor(options.length / 2),\n transition: 0,\n items: options,\n })\n\n const itemsShownCount = 5\n const shownItems = getNeighbours(range(items.length), currentIndex).map(index => ({\n name: mapping(items[index]!), index\n }))\n\n const itemHeight = 40\n const distance = 8\n\n const containerHeight = itemHeight * (itemsShownCount - 2) + distance * (itemsShownCount - 2 + 1)\n\n const getDirection = useCallback((targetIndex: number, currentIndex: number, transition: number, length: number): Direction => {\n if (targetIndex === currentIndex) {\n return transition > 0 ? up : down\n }\n let distanceForward = targetIndex - currentIndex\n if (distanceForward < 0) {\n distanceForward += length\n }\n return distanceForward >= length / 2 ? down : up\n }, [])\n\n const animate = useCallback((timestamp: number, startTime: number | undefined) => {\n setAnimation((prevState) => {\n const {\n targetIndex,\n currentIndex,\n transition,\n animationVelocity,\n velocity,\n items,\n lastScrollTimeStamp\n } = prevState\n if (disabled) {\n return { ...prevState, currentIndex: targetIndex, velocity: 0, lastTimeStamp: timestamp }\n }\n if ((targetIndex === currentIndex && velocity === 0 && transition === 0) || !startTime) {\n return { ...prevState, lastTimeStamp: timestamp }\n }\n const progress = (timestamp - startTime) / 1000 // to seconds\n const direction = getDirection(targetIndex, currentIndex, transition, items.length)\n\n let newVelocity = velocity\n let usedVelocity\n let newCurrentIndex = currentIndex\n const isAutoScrolling = velocity === 0 && (!lastScrollTimeStamp || timestamp - lastScrollTimeStamp > 300)\n\n const newLastScrollTimeStamp = velocity !== 0 ? timestamp : lastScrollTimeStamp\n\n // manual scrolling\n if (isAutoScrolling) {\n usedVelocity = direction * animationVelocity\n } else {\n usedVelocity = velocity\n newVelocity = velocity * 0.5 // drag loss\n if (Math.abs(newVelocity) <= 0.05) {\n newVelocity = 0\n }\n }\n\n let newTransition = transition + usedVelocity * progress\n const changeThreshold = 0.5\n\n while (newTransition >= changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition >= changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = (currentIndex + 1) % items.length\n newTransition -= 1\n }\n if (newTransition >= changeThreshold) {\n newTransition = 0\n }\n while (newTransition <= -changeThreshold) {\n if (newCurrentIndex === targetIndex && newTransition <= -changeThreshold && isAutoScrolling) {\n newTransition = 0\n break\n }\n newCurrentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1\n newTransition += 1\n }\n let newTargetIndex = targetIndex\n if (!isAutoScrolling) {\n newTargetIndex = newCurrentIndex\n }\n\n if ((currentIndex !== newTargetIndex || newTargetIndex !== targetIndex) && newTargetIndex === newCurrentIndex) {\n onChange(items[newCurrentIndex]!)\n }\n return {\n targetIndex: newTargetIndex,\n currentIndex: newCurrentIndex,\n animationVelocity,\n transition: newTransition,\n velocity: newVelocity,\n items,\n lastTimeStamp: timestamp,\n lastScrollTimeStamp: newLastScrollTimeStamp\n }\n })\n }, [disabled, getDirection, onChange])\n\n useEffect(() => {\n // constant update\n requestAnimationFrame((timestamp) => animate(timestamp, lastTimeStamp))\n })\n\n const opacity = (transition: number, index: number, itemsCount: number) => {\n const max = 100\n const min = 0\n const distance = max - min\n\n let opacityValue = min\n const unitTransition = clamp((transition) / 0.5)\n if (index === 1 || index === itemsCount - 2) {\n if (index === 1 && transition > 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n if (index === itemsCount - 2 && transition < 0) {\n opacityValue += Math.floor(unitTransition * distance)\n }\n } else {\n opacityValue = max\n }\n\n // TODO this is not the right value for the bottom entry\n return clamp(1 - (opacityValue / max))\n }\n\n return (\n <div\n className=\"relative overflow-hidden\"\n style={{ height: containerHeight }}\n onWheel={event => {\n if (event.deltaY !== 0) {\n // TODO slower increase\n setAnimation(({ velocity, ...animationData }) =>\n ({ ...animationData, velocity: velocity + event.deltaY }))\n }\n }}\n >\n <div className=\"absolute top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2\">\n <div\n className=\"absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-divider/50 border-y-2 border-x-0 \"\n style={{ height: `${itemHeight}px` }}\n />\n <div\n className=\"flex-col-2 select-none\"\n style={{\n transform: `translateY(${-transition * (distance + itemHeight)}px)`,\n columnGap: `${distance}px`,\n }}\n >\n {shownItems.map(({ name, index }, arrayIndex) => (\n <div\n key={index}\n className={clsx(\n `flex-col-2 items-center justify-center rounded-md`,\n {\n 'text-primary font-bold': currentIndex === index,\n 'text-on-background': currentIndex === index,\n 'cursor-pointer': !disabled,\n 'cursor-not-allowed': disabled,\n }\n )}\n style={{\n opacity: currentIndex !== index ? opacity(transition, arrayIndex, shownItems.length) : undefined,\n height: `${itemHeight}px`,\n maxHeight: `${itemHeight}px`,\n }}\n onClick={() => !disabled && setAnimation(prevState => ({ ...prevState, targetIndex: index }))}\n >\n {name}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\nexport type RangeOptions = {\n /** Whether the range can be defined empty via end < start without a warning */\n allowEmptyRange: boolean,\n stepSize: number,\n exclusiveStart: boolean,\n exclusiveEnd: boolean,\n}\n\nconst defaultRangeOptions: RangeOptions = {\n allowEmptyRange: false,\n stepSize: 1,\n exclusiveStart: false,\n exclusiveEnd: true,\n}\n\n/**\n * @param endOrRange The end value or a range [start, end], end is exclusive\n * @param options the options for defining the range\n */\nexport const range = (endOrRange: number | [number, number], options?: Partial<RangeOptions>): number[] => {\n const { allowEmptyRange, stepSize, exclusiveStart, exclusiveEnd } = { ...defaultRangeOptions, ...options }\n let start = 0\n let end: number\n if (typeof endOrRange === 'number') {\n end = endOrRange\n } else {\n start = endOrRange[0]\n end = endOrRange[1]\n }\n if (!exclusiveEnd) {\n end -= 1\n }\n if (exclusiveStart) {\n start += 1\n }\n\n if (end - 1 < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set options.allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start }, (_, index) => index * stepSize + 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","export const clamp = (value: number, min: number = 0, max: number = 1): number => {\n return Math.min(Math.max(value, min), max)\n}\n"],"mappings":"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","names":["currentIndex","transition","items","distance"]}
@@ -1,14 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { LabelProps } from './Label.mjs';
4
- import { TileProps } from '../layout-and-navigation/Tile.mjs';
5
4
  import { MenuProps, MenuBag } from './Menu.mjs';
6
5
  import { UseSearchProps } from '../../hooks/useSearch.mjs';
7
6
  import '../../util/PropsWithFunctionChildren.mjs';
8
7
  import '../../hooks/usePopoverPosition.mjs';
9
8
 
10
- type SelectTileProps = TileProps;
11
- declare const SelectTile: ({ className, disabledClassName, title, ...restProps }: SelectTileProps) => react_jsx_runtime.JSX.Element;
12
9
  type SelectOption<T> = {
13
10
  label: ReactNode;
14
11
  value: T;
@@ -41,4 +38,4 @@ type SelectProps<T> = Omit<MenuProps<HTMLButtonElement>, 'trigger' | 'children'>
41
38
  declare const Select: <T>({ value, label, options, onChange, hintText, selectedDisplayOverwrite, searchOptions, additionalItems, className, triggerClassName, hintTextClassName, ...menuProps }: SelectProps<T>) => react_jsx_runtime.JSX.Element;
42
39
  declare const SelectUncontrolled: <T>({ options, onChange, value, hintText, ...props }: SelectProps<T>) => react_jsx_runtime.JSX.Element;
43
40
 
44
- export { Select, type SelectBag, type SelectOption, type SelectProps, SelectTile, type SelectTileProps, SelectUncontrolled };
41
+ export { Select, type SelectBag, type SelectOption, type SelectProps, SelectUncontrolled };
@@ -1,14 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { LabelProps } from './Label.js';
4
- import { TileProps } from '../layout-and-navigation/Tile.js';
5
4
  import { MenuProps, MenuBag } from './Menu.js';
6
5
  import { UseSearchProps } from '../../hooks/useSearch.js';
7
6
  import '../../util/PropsWithFunctionChildren.js';
8
7
  import '../../hooks/usePopoverPosition.js';
9
8
 
10
- type SelectTileProps = TileProps;
11
- declare const SelectTile: ({ className, disabledClassName, title, ...restProps }: SelectTileProps) => react_jsx_runtime.JSX.Element;
12
9
  type SelectOption<T> = {
13
10
  label: ReactNode;
14
11
  value: T;
@@ -41,4 +38,4 @@ type SelectProps<T> = Omit<MenuProps<HTMLButtonElement>, 'trigger' | 'children'>
41
38
  declare const Select: <T>({ value, label, options, onChange, hintText, selectedDisplayOverwrite, searchOptions, additionalItems, className, triggerClassName, hintTextClassName, ...menuProps }: SelectProps<T>) => react_jsx_runtime.JSX.Element;
42
39
  declare const SelectUncontrolled: <T>({ options, onChange, value, hintText, ...props }: SelectProps<T>) => react_jsx_runtime.JSX.Element;
43
40
 
44
- export { Select, type SelectBag, type SelectOption, type SelectProps, SelectTile, type SelectTileProps, SelectUncontrolled };
41
+ export { Select, type SelectBag, type SelectOption, type SelectProps, SelectUncontrolled };
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var Select_exports = {};
31
31
  __export(Select_exports, {
32
32
  Select: () => Select,
33
- SelectTile: () => SelectTile,
34
33
  SelectUncontrolled: () => SelectUncontrolled
35
34
  });
36
35
  module.exports = __toCommonJS(Select_exports);
@@ -62,14 +61,16 @@ var import_lucide_react = require("lucide-react");
62
61
  var import_jsx_runtime2 = require("react/jsx-runtime");
63
62
  var Tile = ({
64
63
  title,
64
+ titleClassName,
65
65
  description,
66
+ descriptionClassName,
66
67
  onClick,
67
68
  isSelected = false,
68
69
  disabled = false,
69
70
  prefix,
70
71
  suffix,
71
72
  normalClassName = "hover:bg-primary/40 cursor-pointer",
72
- selectedClassName = " bg-primary/20",
73
+ selectedClassName = "bg-primary/20",
73
74
  disabledClassName = "text-disabled-text bg-disabled-background cursor-not-allowed",
74
75
  className
75
76
  }) => {
@@ -79,7 +80,7 @@ var Tile = ({
79
80
  className: (0, import_clsx2.default)(
80
81
  "flex-row-2 w-full items-center",
81
82
  {
82
- [normalClassName]: !!onClick && !disabled,
83
+ [normalClassName]: onClick && !disabled,
83
84
  [selectedClassName]: isSelected && !disabled,
84
85
  [disabledClassName]: disabled
85
86
  },
@@ -89,14 +90,27 @@ var Tile = ({
89
90
  children: [
90
91
  prefix,
91
92
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-col-0 w-full", children: [
92
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: (0, import_clsx2.default)(title.className ?? "textstyle-title-normal"), children: title.value }),
93
- !!description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: (0, import_clsx2.default)(description.className ?? "textstyle-description"), children: description.value })
93
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: (0, import_clsx2.default)(titleClassName ?? "textstyle-title-normal"), children: title }),
94
+ !!description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: (0, import_clsx2.default)(descriptionClassName ?? "textstyle-description"), children: description })
94
95
  ] }),
95
96
  suffix ?? (isSelected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Check, { size: 24 }) : void 0)
96
97
  ]
97
98
  }
98
99
  );
99
100
  };
101
+ var ListTile = ({
102
+ ...props
103
+ }) => {
104
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
105
+ Tile,
106
+ {
107
+ ...props,
108
+ titleClassName: props.titleClassName ?? "font-semibold",
109
+ className: (0, import_clsx2.default)("px-2 py-1 rounded-md", props.className),
110
+ disabledClassName: props.disabledClassName ?? "text-disabled-text cursor-not-allowed"
111
+ }
112
+ );
113
+ };
100
114
 
101
115
  // src/components/layout-and-navigation/Expandable.tsx
102
116
  var import_react = require("react");
@@ -1107,22 +1121,6 @@ var useSearch = ({
1107
1121
 
1108
1122
  // src/components/user-action/Select.tsx
1109
1123
  var import_jsx_runtime9 = require("react/jsx-runtime");
1110
- var SelectTile = ({
1111
- className,
1112
- disabledClassName,
1113
- title,
1114
- ...restProps
1115
- }) => {
1116
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1117
- Tile,
1118
- {
1119
- ...restProps,
1120
- className: (0, import_clsx8.default)("px-2 py-1 rounded-md", className),
1121
- disabledClassName: disabledClassName ?? "text-disabled-text cursor-not-allowed",
1122
- title: { ...title, className: title.className ?? "font-semibold" }
1123
- }
1124
- );
1125
- };
1126
1124
  var Select = ({
1127
1125
  value,
1128
1126
  label,
@@ -1189,10 +1187,10 @@ var Select = ({
1189
1187
  ),
1190
1188
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-col-2 overflow-y-auto", children: [
1191
1189
  result.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1192
- SelectTile,
1190
+ ListTile,
1193
1191
  {
1194
1192
  isSelected: option === selectedOption,
1195
- title: { value: option.label },
1193
+ title: option.label,
1196
1194
  onClick: () => {
1197
1195
  onChange(option.value);
1198
1196
  close();
@@ -1239,7 +1237,6 @@ var SelectUncontrolled = ({
1239
1237
  // Annotate the CommonJS export names for ESM import in node:
1240
1238
  0 && (module.exports = {
1241
1239
  Select,
1242
- SelectTile,
1243
1240
  SelectUncontrolled
1244
1241
  });
1245
1242
  //# sourceMappingURL=Select.js.map