@helpwave/hightide-native 0.6.0 → 0.9.0

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 (88) hide show
  1. package/package.json +6 -8
  2. package/src/components/card/Card.tsx +2 -4
  3. package/src/components/chat/ChatAttachmentMessageBubble.tsx +152 -90
  4. package/src/components/chat/ChatConversationList.tsx +4 -12
  5. package/src/components/chat/ChatConversationRow.tsx +159 -164
  6. package/src/components/chat/ChatDateDivider.tsx +3 -8
  7. package/src/components/chat/ChatMessageBubble.tsx +52 -45
  8. package/src/components/chat/ChatMessageComposer.tsx +4 -12
  9. package/src/components/chat/ChatMessageList.tsx +3 -9
  10. package/src/components/chat/ChatQuickReplyChip.tsx +41 -27
  11. package/src/components/chat/ChatSystemLine.tsx +4 -12
  12. package/src/components/chat/ChatThreadHeader.tsx +136 -101
  13. package/src/components/layout/Divider.tsx +2 -4
  14. package/src/components/list/ListActionItem.tsx +57 -65
  15. package/src/components/list/ListItem.tsx +8 -28
  16. package/src/components/list/ListItemTextContent.tsx +4 -2
  17. package/src/components/list/ListNavigationItem.tsx +55 -63
  18. package/src/components/user-interaction/Button.tsx +43 -49
  19. package/src/components/user-interaction/Checkbox.tsx +47 -48
  20. package/src/components/user-interaction/IconButton.tsx +40 -42
  21. package/src/components/user-interaction/Input.tsx +69 -80
  22. package/src/components/user-interaction/MultiSelect/MultiSelect.tsx +17 -0
  23. package/src/components/user-interaction/MultiSelect/MultiSelectComponent.tsx +40 -0
  24. package/src/components/user-interaction/MultiSelect/MultiSelectContext.tsx +74 -0
  25. package/src/components/user-interaction/MultiSelect/MultiSelectMenu.tsx +87 -0
  26. package/src/components/user-interaction/MultiSelect/MultiSelectOption.tsx +106 -0
  27. package/src/components/user-interaction/MultiSelect/MultiSelectRoot.tsx +194 -0
  28. package/src/components/user-interaction/MultiSelect/MultiSelectTrigger.tsx +123 -0
  29. package/src/components/user-interaction/MultiSelect/index.ts +2 -0
  30. package/src/components/user-interaction/SearchBar.tsx +11 -17
  31. package/src/components/user-interaction/Select/Select.tsx +17 -0
  32. package/src/components/user-interaction/Select/SelectComponent.tsx +40 -0
  33. package/src/components/user-interaction/Select/SelectContext.tsx +73 -0
  34. package/src/components/user-interaction/Select/SelectMenu.tsx +87 -0
  35. package/src/components/user-interaction/Select/SelectOption.tsx +96 -0
  36. package/src/components/user-interaction/Select/SelectRoot.tsx +186 -0
  37. package/src/components/user-interaction/Select/SelectTrigger.tsx +92 -0
  38. package/src/components/user-interaction/Select/index.ts +2 -0
  39. package/src/components/user-interaction/Switch.tsx +46 -98
  40. package/src/components/user-interaction/Textarea.tsx +165 -12
  41. package/src/components/user-interaction/ThemedPressable.tsx +48 -49
  42. package/src/components/visualization-and-display/Avatar.tsx +19 -17
  43. package/src/components/visualization-and-display/Chip.tsx +4 -12
  44. package/src/components/visualization-and-display/ThemedText.tsx +12 -5
  45. package/src/enums/chatMessageDirection.ts +18 -0
  46. package/src/enums/chatMessageStatus.ts +18 -0
  47. package/src/enums/hightideThemeModes.ts +18 -0
  48. package/src/enums/index.ts +7 -0
  49. package/src/enums/listItemContentOrder.ts +18 -0
  50. package/src/enums/themedTextAppearance.ts +18 -0
  51. package/src/enums/useMultiSelectFirstHighlightBehavior.ts +18 -0
  52. package/src/enums/useSelectFirstHighlightBehavior.ts +18 -0
  53. package/src/global-contexts/content-theme/ContentThemeProvider.tsx +9 -5
  54. package/src/global-contexts/theme/ThemeProvider.tsx +4 -1
  55. package/src/hooks/index.ts +2 -0
  56. package/src/hooks/useAnimatedStyleTransition.ts +460 -0
  57. package/src/hooks/useMemoizedTheme.ts +23 -0
  58. package/src/hooks/useMultiSelect.ts +3 -1
  59. package/src/hooks/useSelect.ts +3 -1
  60. package/src/icons/HightideIconRegistry.ts +2 -0
  61. package/src/theme/adapters/style-adapter-utils.ts +121 -27
  62. package/src/theme/resolvers/avatar.ts +48 -39
  63. package/src/theme/resolvers/button.ts +7 -17
  64. package/src/theme/resolvers/chat/attachment-message-bubble.ts +5 -6
  65. package/src/theme/resolvers/chat/conversation-row.ts +4 -6
  66. package/src/theme/resolvers/chat/message-bubble.ts +1 -2
  67. package/src/theme/resolvers/chat/message-composer.ts +1 -2
  68. package/src/theme/resolvers/chat/quick-reply-chip.ts +2 -3
  69. package/src/theme/resolvers/chat/system-line.ts +1 -2
  70. package/src/theme/resolvers/chat/thread-header.ts +3 -4
  71. package/src/theme/resolvers/checkbox.ts +2 -2
  72. package/src/theme/resolvers/chip.ts +1 -2
  73. package/src/theme/resolvers/iconButton.ts +4 -13
  74. package/src/theme/resolvers/input.ts +30 -14
  75. package/src/theme/resolvers/listItem.ts +2 -3
  76. package/src/theme/resolvers/multiSelect.ts +1 -2
  77. package/src/theme/resolvers/searchBar.ts +1 -2
  78. package/src/theme/resolvers/select.ts +1 -2
  79. package/src/theme/resolvers/themedPressable.ts +4 -15
  80. package/src/theme/themes/hightideThemes.ts +3 -1
  81. package/src/theme/types/components/chat.ts +6 -21
  82. package/src/theme/types/components/input.ts +3 -0
  83. package/src/theme/types/components/textarea.ts +1 -0
  84. package/src/theme/types/resolver.ts +4 -27
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/pressableInteraction.ts +7 -0
  87. package/src/components/user-interaction/MultiSelect.tsx +0 -282
  88. package/src/components/user-interaction/Select.tsx +0 -242
@@ -1,4 +1,4 @@
1
- import { Fragment, forwardRef } from 'react'
1
+ import { forwardRef, useMemo, useState } from 'react'
2
2
  import {
3
3
  Pressable,
4
4
  View,
@@ -15,6 +15,7 @@ import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
15
15
  import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
16
16
  import { useDebugContext } from '../../global-contexts/debug'
17
17
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
18
+ import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
18
19
  import type {
19
20
  ThemedPressableIconStyle,
20
21
  ThemedPressableState,
@@ -45,13 +46,6 @@ export type ThemedPressableProps = Omit<PressableProps, 'style'> & {
45
46
  textStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableTextStyle>,
46
47
  }
47
48
 
48
- type PressableInteraction = {
49
- pressed: boolean,
50
- hovered?: boolean,
51
- focused?: boolean,
52
- focusVisible?: boolean,
53
- }
54
-
55
49
  export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>, ThemedPressableProps>(function ThemedPressable({
56
50
  children,
57
51
  size = 'md',
@@ -75,19 +69,33 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
75
69
  hitSlop: providedHitSlop,
76
70
  onLayout: providedOnLayout,
77
71
  })
72
+ const [isPressed, setIsPressed] = useState(false)
78
73
 
79
- const resolveState = (interaction: PressableInteraction): ThemedPressableState => ({
74
+ const resolvedState = useMemo((): ThemedPressableState => ({
80
75
  size,
81
76
  color,
82
77
  coloringStyle,
83
78
  coloringColorVariant,
84
79
  hasAdditionalHorizontalPadding,
85
80
  isDisabled: !!disabled,
86
- isPressed: interaction.pressed,
87
- isHovered: !!interaction.hovered,
88
- isFocused: !!interaction.focused,
89
- isFocusVisible: !!interaction.focusVisible,
90
- })
81
+ isPressed,
82
+ }), [
83
+ size,
84
+ color,
85
+ coloringStyle,
86
+ coloringColorVariant,
87
+ hasAdditionalHorizontalPadding,
88
+ disabled,
89
+ isPressed,
90
+ ])
91
+
92
+ const resolvedContainerStyle = useMemoizedTheme(theme.components.themedPressable.container, resolvedState, style)
93
+ const resolvedStateLayerStyle = useMemoizedTheme(theme.components.themedPressable.stateLayer, resolvedState, stateLayerStyle)
94
+ const resolvedTextStyle = useMemoizedTheme(theme.components.themedPressable.text, resolvedState, textStyle)
95
+ const resolvedIconStyle = useMemoizedTheme(theme.components.themedPressable.icon, resolvedState, iconStyle)
96
+ const resolvedChildren = typeof children === 'function'
97
+ ? children({ pressed: isPressed })
98
+ : children
91
99
 
92
100
  return (
93
101
  <Pressable
@@ -96,43 +104,34 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
96
104
  disabled={disabled}
97
105
  hitSlop={hitSlop}
98
106
  onLayout={onLayout}
99
- style={(pressableState) => {
100
- const state = resolveState(pressableState)
101
- return theme.components.themedPressable.container(state, style)
107
+ style={resolvedContainerStyle}
108
+ onPressIn={(event) => {
109
+ setIsPressed(true)
110
+ props.onPressIn?.(event)
102
111
  }}
103
- >
104
- {(pressableState) => {
105
- const state = resolveState(pressableState)
106
- const resolvedText = theme.components.themedPressable.text(state, textStyle)
107
- const resolvedIcon = theme.components.themedPressable.icon(state, iconStyle)
108
- const resolvedChildren = typeof children === 'function'
109
- ? children(pressableState)
110
- : children
111
- const backroundColor = theme.components.themedPressable.container(state, style).backgroundColor
112
-
113
- return (
114
- <Fragment>
115
- {hitBox.isVisualizing && (
116
- <View
117
- pointerEvents="none"
118
- style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
119
- />
120
- )}
121
- <View
122
- pointerEvents="none"
123
- style={theme.components.themedPressable.stateLayer(state, stateLayerStyle)}
124
- />
125
- <ContentThemeOverrideProvider
126
- foreground={resolvedText.color}
127
- background={backroundColor}
128
- textStyle={resolvedText}
129
- iconStyle={resolvedIcon}
130
- >
131
- {resolvedChildren}
132
- </ContentThemeOverrideProvider>
133
- </Fragment>
134
- )
112
+ onPressOut={(event) => {
113
+ setIsPressed(false)
114
+ props.onPressOut?.(event)
135
115
  }}
116
+ >
117
+ {hitBox.isVisualizing && (
118
+ <View
119
+ pointerEvents="none"
120
+ style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
121
+ />
122
+ )}
123
+ <View
124
+ pointerEvents="none"
125
+ style={resolvedStateLayerStyle}
126
+ />
127
+ <ContentThemeOverrideProvider
128
+ foreground={resolvedTextStyle.color}
129
+ background={resolvedContainerStyle.backgroundColor}
130
+ textStyle={resolvedTextStyle}
131
+ iconStyle={resolvedIconStyle}
132
+ >
133
+ {resolvedChildren}
134
+ </ContentThemeOverrideProvider>
136
135
  </Pressable>
137
136
  )
138
137
  })
@@ -22,6 +22,7 @@ import {
22
22
  import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
23
23
 
24
24
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
25
+ import { useMemoizedTheme, useMemoizedThemeFactory } from '../../hooks/useMemoizedTheme'
25
26
  import type {
26
27
  AvatarGroupContainerStyle,
27
28
  AvatarGroupStackStyle,
@@ -32,6 +33,7 @@ import type {
32
33
  AvatarStatus,
33
34
  AvatarStyle,
34
35
  AvatarTextStyle,
36
+ AvatarThemeResolvers,
35
37
  AvatarStatusDotStyle,
36
38
  AvatarWithStatusState
37
39
  } from '../../theme/types/components/avatar'
@@ -126,10 +128,10 @@ export const Avatar = ({
126
128
  setImage(initialImage)
127
129
  }, [image?.avatarUrl, initialImage])
128
130
 
129
- const resolvedAvatar = theme.components.avatar.container(state, avatarStyle)
130
- const resolvedImage = theme.components.avatar.image(state, imageStyle)
131
- const resolvedText = theme.components.avatar.text(state, textStyle)
132
- const resolvedIcon = theme.components.avatar.icon(state, iconStyle)
131
+ const resolvedAvatar = useMemoizedTheme(theme.components.avatar.container, state, avatarStyle)
132
+ const resolvedImage = useMemoizedTheme(theme.components.avatar.image, state, imageStyle)
133
+ const resolvedText = useMemoizedTheme(theme.components.avatar.text, state, textStyle)
134
+ const resolvedIcon = useMemoizedTheme(theme.components.avatar.icon, state, iconStyle)
133
135
 
134
136
  return (
135
137
  <View
@@ -196,13 +198,13 @@ export const AvatarGroup = ({
196
198
  count: displayedProfiles.length,
197
199
  }), [size, color, displayedProfiles.length])
198
200
 
199
- const avatarResolvers = useMemo(
200
- () => theme.components.avatarGroup.avatar(state),
201
- [theme, state]
202
- )
203
- const resolvedContainer = theme.components.avatarGroup.container(state, containerStyle)
204
- const resolvedAvatarStack = theme.components.avatarGroup.avatarStack(state, avatarStackStyle)
205
- const resolvedText = theme.components.avatarGroup.text(state, textStyle)
201
+ const avatarResolvers = useMemoizedThemeFactory<
202
+ AvatarState,
203
+ AvatarThemeResolvers
204
+ >(theme.components.avatarGroup.avatar, state)
205
+ const resolvedContainer = useMemoizedTheme(theme.components.avatarGroup.container, state, containerStyle)
206
+ const resolvedAvatarStack = useMemoizedTheme(theme.components.avatarGroup.avatarStack, state, avatarStackStyle)
207
+ const resolvedText = useMemoizedTheme(theme.components.avatarGroup.text, state, textStyle)
206
208
 
207
209
  return (
208
210
  <View
@@ -282,14 +284,14 @@ export const AvatarWithStatus = ({
282
284
  status,
283
285
  }), [size, color, status])
284
286
 
285
- const avatarResolvers = useMemo(
286
- () => theme.components.avatarWithStatus.avatar(state),
287
- [theme, state]
288
- )
289
- const resolvedStatusDot = theme.components.avatarWithStatus.statusDot(state, statusDotStyle)
287
+ const avatarResolvers = useMemoizedThemeFactory<
288
+ AvatarWithStatusState,
289
+ AvatarThemeResolvers
290
+ >(theme.components.avatarWithStatus.avatar, state)
291
+ const resolvedStatusDot = useMemoizedTheme(theme.components.avatarWithStatus.statusDot, state, statusDotStyle)
290
292
 
291
293
  return (
292
- <View style={[{ position: 'relative' }, style]}>
294
+ <View style={[{ position: 'relative', alignSelf: 'flex-start' }, style]}>
293
295
  <Avatar
294
296
  {...avatarProps}
295
297
  size={size}
@@ -14,6 +14,7 @@ import type { ChipVariant, ComponentSize } from '@helpwave/hightide-design/seman
14
14
 
15
15
  import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
16
16
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
17
+ import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
17
18
  import type {
18
19
  ChipIconStyle,
19
20
  ChipState,
@@ -62,18 +63,9 @@ export const Chip = ({
62
63
  variant,
63
64
  }), [size, color, variant])
64
65
 
65
- const resolvedChipStyle = useMemo(
66
- () => theme.components.chip.chip(state, chipStyle),
67
- [theme, state, chipStyle]
68
- )
69
- const resolvedIconStyle = useMemo(
70
- () => theme.components.chip.icon(state, iconStyle),
71
- [theme, state, iconStyle]
72
- )
73
- const resolvedTextStyle = useMemo(
74
- () => theme.components.chip.text(state, textStyle),
75
- [theme, state, textStyle]
76
- )
66
+ const resolvedChipStyle = useMemoizedTheme(theme.components.chip.chip, state, chipStyle)
67
+ const resolvedIconStyle = useMemoizedTheme(theme.components.chip.icon, state, iconStyle)
68
+ const resolvedTextStyle = useMemoizedTheme(theme.components.chip.text, state, textStyle)
77
69
 
78
70
  return (
79
71
  <View
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  forwardRef
3
3
  } from 'react'
4
+ import type {
5
+ ColorValue } from 'react-native'
4
6
  import {
5
7
  Text as RNText,
6
8
  type TextProps
@@ -9,7 +11,10 @@ import {
9
11
  import { useContentTheme } from '../../global-contexts/content-theme/ContentThemeContext'
10
12
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
11
13
 
12
- export type ThemedTextAppearance = 'normal' | 'description'
14
+ import type { ThemedTextAppearance } from '../../enums/themedTextAppearance'
15
+ import { HexColorUtils } from '../../utils'
16
+
17
+ export type { ThemedTextAppearance }
13
18
 
14
19
  export type ThemedTextProps = TextProps & {
15
20
  appearance?: ThemedTextAppearance,
@@ -22,20 +27,22 @@ export const ThemedText = forwardRef<React.ComponentRef<typeof RNText>, ThemedTe
22
27
  }, ref) {
23
28
  const { theme } = useTheme()
24
29
  const { foreground, background, textStyle } = useContentTheme()
25
- const color = appearance === 'description'
30
+ let color: ColorValue | undefined = textStyle.color ?? foreground
31
+ color = appearance === 'description'
26
32
  ? theme.semantics.asDescription({
27
33
  colorPair: {
28
34
  color: background,
29
- onColor: foreground,
35
+ onColor: HexColorUtils.parseColorValue(color),
30
36
  },
31
37
  })
32
- : undefined
38
+ : color
39
+
33
40
 
34
41
  return (
35
42
  <RNText
36
43
  {...props}
37
44
  ref={ref}
38
- style={[textStyle, color === undefined ? undefined : { color }, style]}
45
+ style={[textStyle, { color }, style]}
39
46
  />
40
47
  )
41
48
  })
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const chatMessageDirectionValues = ['incoming', 'outgoing'] as const
4
+ export type ChatMessageDirection = (typeof chatMessageDirectionValues)[number]
5
+ const allowedChatMessageDirectionValues: ReadonlySet<string> = new Set(
6
+ chatMessageDirectionValues
7
+ )
8
+ function isChatMessageDirectionValue(value: unknown): value is ChatMessageDirection {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedChatMessageDirectionValues.has(value)
13
+ }
14
+ export const ChatMessageDirectionUtils: EnumUtilsType<ChatMessageDirection> = {
15
+ values: chatMessageDirectionValues,
16
+ set: allowedChatMessageDirectionValues,
17
+ isValue: isChatMessageDirectionValue,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const chatMessageStatusValues = ['sent', 'sending', 'received', 'read'] as const
4
+ export type ChatMessageStatus = (typeof chatMessageStatusValues)[number]
5
+ const allowedChatMessageStatusValues: ReadonlySet<string> = new Set(
6
+ chatMessageStatusValues
7
+ )
8
+ function isChatMessageStatusValue(value: unknown): value is ChatMessageStatus {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedChatMessageStatusValues.has(value)
13
+ }
14
+ export const ChatMessageStatusUtils: EnumUtilsType<ChatMessageStatus> = {
15
+ values: chatMessageStatusValues,
16
+ set: allowedChatMessageStatusValues,
17
+ isValue: isChatMessageStatusValue,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const hightideThemeModesValues = ['dark', 'light'] as const
4
+ export type HightideThemeModes = (typeof hightideThemeModesValues)[number]
5
+ const allowedHightideThemeModesValues: ReadonlySet<string> = new Set(
6
+ hightideThemeModesValues
7
+ )
8
+ function isHightideThemeModesValue(value: unknown): value is HightideThemeModes {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedHightideThemeModesValues.has(value)
13
+ }
14
+ export const HightideThemeModesUtils: EnumUtilsType<HightideThemeModes> = {
15
+ values: hightideThemeModesValues,
16
+ set: allowedHightideThemeModesValues,
17
+ isValue: isHightideThemeModesValue,
18
+ }
@@ -0,0 +1,7 @@
1
+ export * from './chatMessageDirection'
2
+ export * from './chatMessageStatus'
3
+ export * from './hightideThemeModes'
4
+ export * from './listItemContentOrder'
5
+ export * from './themedTextAppearance'
6
+ export * from './useMultiSelectFirstHighlightBehavior'
7
+ export * from './useSelectFirstHighlightBehavior'
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const listItemContentOrderValues = ['titleFirst', 'subtitleFirst'] as const
4
+ export type ListItemContentOrder = (typeof listItemContentOrderValues)[number]
5
+ const allowedListItemContentOrderValues: ReadonlySet<string> = new Set(
6
+ listItemContentOrderValues
7
+ )
8
+ function isListItemContentOrderValue(value: unknown): value is ListItemContentOrder {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedListItemContentOrderValues.has(value)
13
+ }
14
+ export const ListItemContentOrderUtils: EnumUtilsType<ListItemContentOrder> = {
15
+ values: listItemContentOrderValues,
16
+ set: allowedListItemContentOrderValues,
17
+ isValue: isListItemContentOrderValue,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const themedTextAppearanceValues = ['normal', 'description'] as const
4
+ export type ThemedTextAppearance = (typeof themedTextAppearanceValues)[number]
5
+ const allowedThemedTextAppearanceValues: ReadonlySet<string> = new Set(
6
+ themedTextAppearanceValues
7
+ )
8
+ function isThemedTextAppearanceValue(value: unknown): value is ThemedTextAppearance {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedThemedTextAppearanceValues.has(value)
13
+ }
14
+ export const ThemedTextAppearanceUtils: EnumUtilsType<ThemedTextAppearance> = {
15
+ values: themedTextAppearanceValues,
16
+ set: allowedThemedTextAppearanceValues,
17
+ isValue: isThemedTextAppearanceValue,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const useMultiSelectFirstHighlightBehaviorValues = ['first', 'last'] as const
4
+ export type UseMultiSelectFirstHighlightBehavior = (typeof useMultiSelectFirstHighlightBehaviorValues)[number]
5
+ const allowedUseMultiSelectFirstHighlightBehaviorValues: ReadonlySet<string> = new Set(
6
+ useMultiSelectFirstHighlightBehaviorValues
7
+ )
8
+ function isUseMultiSelectFirstHighlightBehaviorValue(value: unknown): value is UseMultiSelectFirstHighlightBehavior {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedUseMultiSelectFirstHighlightBehaviorValues.has(value)
13
+ }
14
+ export const UseMultiSelectFirstHighlightBehaviorUtils: EnumUtilsType<UseMultiSelectFirstHighlightBehavior> = {
15
+ values: useMultiSelectFirstHighlightBehaviorValues,
16
+ set: allowedUseMultiSelectFirstHighlightBehaviorValues,
17
+ isValue: isUseMultiSelectFirstHighlightBehaviorValue,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { EnumUtilsType } from '@helpwave/hightide-utils/utils'
2
+
3
+ const useSelectFirstHighlightBehaviorValues = ['first', 'last'] as const
4
+ export type UseSelectFirstHighlightBehavior = (typeof useSelectFirstHighlightBehaviorValues)[number]
5
+ const allowedUseSelectFirstHighlightBehaviorValues: ReadonlySet<string> = new Set(
6
+ useSelectFirstHighlightBehaviorValues
7
+ )
8
+ function isUseSelectFirstHighlightBehaviorValue(value: unknown): value is UseSelectFirstHighlightBehavior {
9
+ if (typeof value !== 'string') {
10
+ return false
11
+ }
12
+ return allowedUseSelectFirstHighlightBehaviorValues.has(value)
13
+ }
14
+ export const UseSelectFirstHighlightBehaviorUtils: EnumUtilsType<UseSelectFirstHighlightBehavior> = {
15
+ values: useSelectFirstHighlightBehaviorValues,
16
+ set: allowedUseSelectFirstHighlightBehaviorValues,
17
+ isValue: isUseSelectFirstHighlightBehaviorValue,
18
+ }
@@ -85,20 +85,24 @@ export const ContentThemeOverrideProvider = ({
85
85
  const newForeground = resolveColorOverride(foregroundOverride, parent.foreground)
86
86
  const newBackground = resolveColorOverride(backgroundOverride, parent.background)
87
87
 
88
- let textStyle = typeof textStyleOverride === 'function'
88
+ const resolvedTextStyleOverride = typeof textStyleOverride === 'function'
89
89
  ? textStyleOverride(parent.textStyle, parent.foreground)
90
- : textStyleOverride ?? parent.textStyle
90
+ : textStyleOverride
91
+
92
+ let textStyle = resolvedTextStyleOverride ?? parent.textStyle
91
93
 
92
94
  if (!isKeepingTextColor && newForeground !== undefined) {
93
- textStyle = { ...textStyle, color: newForeground }
95
+ textStyle = { ...textStyle, color: resolvedTextStyleOverride?.color ?? newForeground }
94
96
  }
95
97
 
96
- let iconStyle = typeof iconStyleOverride === 'function'
98
+ const resolvedIconStyleOverride = typeof iconStyleOverride === 'function'
97
99
  ? iconStyleOverride(parent.iconStyle, parent.foreground)
98
100
  : iconStyleOverride ?? parent.iconStyle
99
101
 
102
+ let iconStyle = resolvedIconStyleOverride ?? parent.iconStyle
103
+
100
104
  if (!isKeepingIconColor && newForeground !== undefined) {
101
- iconStyle = { ...iconStyle, color: newForeground }
105
+ iconStyle = { ...iconStyle, color: resolvedIconStyleOverride?.color ?? newForeground }
102
106
  }
103
107
 
104
108
  return {
@@ -96,7 +96,10 @@ export const ThemeProvider = ({
96
96
  <ContentThemeRootProvider
97
97
  foreground={contextValue.theme.colors.surface.onColor}
98
98
  background={contextValue.theme.colors.surface.color}
99
- textStyle={contextValue.theme.typography.body.md}
99
+ textStyle={{
100
+ ...contextValue.theme.typography.body.md,
101
+ //color: contextValue.theme.colors.surface.onColor,
102
+ }}
100
103
  iconStyle={{
101
104
  size: contextValue.theme.icongraphy.sizes.md,
102
105
  strokeWidth: contextValue.theme.icongraphy.strokeWidth,
@@ -1,3 +1,5 @@
1
+ export * from './useAnimatedStyleTransition'
2
+ export * from './useMemoizedTheme'
1
3
  export * from './useMultiSelect'
2
4
  export * from './useNativeKeyValueStore'
3
5
  export * from './useSelect'