@helpwave/hightide-native 0.0.8 → 0.1.1

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 (125) hide show
  1. package/README.md +4 -4
  2. package/package.json +8 -19
  3. package/src/components/card/Card.tsx +41 -0
  4. package/src/components/card/index.ts +1 -0
  5. package/src/components/chat/ChatAttachmentMessageBubble.tsx +246 -0
  6. package/src/components/chat/ChatConversationRow.tsx +21 -16
  7. package/src/components/chat/ChatDateDivider.tsx +2 -2
  8. package/src/components/chat/ChatMessageBubble.tsx +62 -52
  9. package/src/components/chat/ChatMessageComposer.tsx +16 -14
  10. package/src/components/chat/ChatQuickReplyChip.tsx +41 -43
  11. package/src/components/chat/ChatSystemLine.tsx +14 -7
  12. package/src/components/chat/ChatThreadHeader.tsx +60 -6
  13. package/src/components/chat/index.ts +1 -2
  14. package/src/components/index.ts +3 -1
  15. package/src/components/layout/Divider.tsx +60 -0
  16. package/src/components/layout/index.ts +1 -0
  17. package/src/components/list/ListActionItem.tsx +99 -0
  18. package/src/components/list/ListItem.tsx +96 -0
  19. package/src/components/list/ListNavigationItem.tsx +102 -0
  20. package/src/components/list/index.ts +3 -0
  21. package/src/components/user-interaction/Button.tsx +80 -31
  22. package/src/components/user-interaction/Checkbox.tsx +72 -32
  23. package/src/components/user-interaction/IconButton.tsx +68 -30
  24. package/src/components/user-interaction/Input.tsx +61 -14
  25. package/src/components/user-interaction/MultiSelect.tsx +142 -75
  26. package/src/components/user-interaction/SearchBar.tsx +222 -0
  27. package/src/components/user-interaction/Select.tsx +129 -58
  28. package/src/components/user-interaction/Switch.tsx +110 -80
  29. package/src/components/user-interaction/ThemedPressable.tsx +136 -0
  30. package/src/components/user-interaction/index.ts +2 -0
  31. package/src/components/visualization-and-display/Avatar.tsx +112 -93
  32. package/src/components/visualization-and-display/Chip.tsx +22 -22
  33. package/src/components/visualization-and-display/ThemedIcon.tsx +72 -0
  34. package/src/components/visualization-and-display/ThemedText.tsx +38 -0
  35. package/src/components/visualization-and-display/index.ts +2 -1
  36. package/src/global-contexts/HightideProvider.tsx +19 -10
  37. package/src/global-contexts/content-theme/ContentThemeContext.ts +22 -0
  38. package/src/global-contexts/content-theme/ContentThemeProvider.tsx +32 -0
  39. package/src/global-contexts/content-theme/index.ts +2 -0
  40. package/src/global-contexts/debug/forward-exports.ts +10 -0
  41. package/src/global-contexts/debug/index.ts +1 -0
  42. package/src/global-contexts/index.ts +2 -0
  43. package/src/global-contexts/theme/ThemeProvider.tsx +7 -1
  44. package/src/icons/HightideIconRegistry.ts +33 -0
  45. package/src/icons/index.ts +2 -0
  46. package/src/icons/types.ts +11 -0
  47. package/src/theme/adapters/container-adapter.ts +323 -0
  48. package/src/theme/adapters/defined.ts +11 -0
  49. package/src/theme/adapters/icon-style-adapter.ts +10 -0
  50. package/src/theme/adapters/index.ts +4 -0
  51. package/src/theme/adapters/text-style-adapter.ts +16 -0
  52. package/src/theme/index.ts +1 -0
  53. package/src/theme/resolvers/avatar.ts +385 -186
  54. package/src/theme/resolvers/button.ts +50 -82
  55. package/src/theme/resolvers/card.ts +27 -0
  56. package/src/theme/resolvers/chat/attachment-message-bubble.ts +163 -0
  57. package/src/theme/resolvers/chat/chat-theme.ts +69 -0
  58. package/src/theme/resolvers/chat/conversation-list.ts +35 -0
  59. package/src/theme/resolvers/chat/conversation-row.ts +64 -0
  60. package/src/theme/resolvers/chat/date-divider.ts +31 -0
  61. package/src/theme/resolvers/chat/index.ts +11 -0
  62. package/src/theme/resolvers/chat/message-bubble.ts +57 -0
  63. package/src/theme/resolvers/chat/message-composer.ts +38 -0
  64. package/src/theme/resolvers/chat/message-list.ts +27 -0
  65. package/src/theme/resolvers/chat/quick-reply-chip.ts +80 -0
  66. package/src/theme/resolvers/chat/system-line.ts +41 -0
  67. package/src/theme/resolvers/chat/thread-header.ts +85 -0
  68. package/src/theme/resolvers/checkbox.ts +87 -74
  69. package/src/theme/resolvers/chip.ts +30 -67
  70. package/src/theme/resolvers/colorScheme.ts +136 -0
  71. package/src/theme/resolvers/divider.ts +34 -0
  72. package/src/theme/resolvers/icon.ts +21 -0
  73. package/src/theme/resolvers/iconButton.ts +45 -61
  74. package/src/theme/resolvers/index.ts +7 -2
  75. package/src/theme/resolvers/input.ts +64 -42
  76. package/src/theme/resolvers/listItem.ts +115 -0
  77. package/src/theme/resolvers/multiSelect.ts +159 -84
  78. package/src/theme/resolvers/searchBar.ts +121 -0
  79. package/src/theme/resolvers/select.ts +141 -66
  80. package/src/theme/resolvers/switch.ts +59 -53
  81. package/src/theme/resolvers/themedPressable.ts +54 -0
  82. package/src/theme/themes/createHightideTheme.ts +214 -51
  83. package/src/theme/themes/hightideThemes.ts +10 -6
  84. package/src/theme/types/color.ts +2 -59
  85. package/src/theme/types/components/avatar.ts +37 -36
  86. package/src/theme/types/components/button.ts +13 -14
  87. package/src/theme/types/components/card.ts +9 -0
  88. package/src/theme/types/components/chat.ts +124 -103
  89. package/src/theme/types/components/checkbox.ts +11 -12
  90. package/src/theme/types/components/chip.ts +8 -14
  91. package/src/theme/types/components/divider.ts +18 -0
  92. package/src/theme/types/components/hightide.ts +41 -42
  93. package/src/theme/types/components/iconButton.ts +19 -14
  94. package/src/theme/types/components/index.ts +5 -1
  95. package/src/theme/types/components/input.ts +17 -8
  96. package/src/theme/types/components/listItem.ts +86 -0
  97. package/src/theme/types/components/multiSelect.ts +14 -12
  98. package/src/theme/types/components/searchBar.ts +28 -0
  99. package/src/theme/types/components/select.ts +21 -9
  100. package/src/theme/types/components/switch.ts +12 -5
  101. package/src/theme/types/components/themedPressable.ts +31 -0
  102. package/src/theme/types/decoration.ts +1 -11
  103. package/src/theme/types/icongraphy.ts +8 -0
  104. package/src/theme/types/index.ts +2 -0
  105. package/src/theme/types/layout.ts +25 -57
  106. package/src/theme/types/resolver.ts +54 -1
  107. package/src/theme/types/semantics.ts +72 -0
  108. package/src/theme/types/theme.ts +26 -13
  109. package/src/theme/types/typography.ts +16 -17
  110. package/src/utils/hitBoxOverlay.ts +44 -0
  111. package/src/utils/index.ts +2 -0
  112. package/src/utils/minimumTouchTargetHitSlop.ts +68 -0
  113. package/src/components/chat/ChatAttachmentCard.tsx +0 -110
  114. package/src/components/chat/ChatMessageCard.tsx +0 -118
  115. package/src/components/menu/Menu.tsx +0 -61
  116. package/src/components/menu/MenuActionItem.tsx +0 -90
  117. package/src/components/menu/MenuItem.tsx +0 -73
  118. package/src/components/menu/MenuNavigationItem.tsx +0 -90
  119. package/src/components/menu/index.ts +0 -4
  120. package/src/components/visualization-and-display/Icon.tsx +0 -27
  121. package/src/storybook/helper.tsx +0 -36
  122. package/src/theme/resolvers/chat.ts +0 -418
  123. package/src/theme/resolvers/coloring.ts +0 -94
  124. package/src/theme/resolvers/menu.ts +0 -120
  125. package/src/theme/types/components/menu.ts +0 -57
@@ -0,0 +1,80 @@
1
+ import type {
2
+ ContainerTokens,
3
+ TextStyleTokens
4
+ } from '@helpwave/hightide-design/component-token-resolvers'
5
+
6
+ import { toContainerStyle } from '../../adapters/container-adapter'
7
+ import { toTextStyle } from '../../adapters/text-style-adapter'
8
+ import type {
9
+ ChatQuickReplyChipState,
10
+ ChatQuickReplyChipThemeResolvers,
11
+ PressableContainerStyle,
12
+ PressableState,
13
+ PressableStateLayerStyle,
14
+ PressableTextStyle
15
+ } from '../../types/components/chat'
16
+ import {
17
+ createStyleResolver,
18
+ createValueResolver,
19
+ toPressableInteractionState,
20
+ type ComponentThemeResolver
21
+ } from '../../types/resolver'
22
+
23
+ const toOptionalContainerStyle = (tokens?: ContainerTokens): PressableContainerStyle => (
24
+ tokens === undefined ? {} : toContainerStyle(tokens)
25
+ )
26
+
27
+ const toOptionalTextStyle = (tokens?: TextStyleTokens): PressableTextStyle => (
28
+ tokens === undefined ? {} : toTextStyle(tokens)
29
+ )
30
+
31
+ export const toChatQuickReplyChipThemeResolvers: ComponentThemeResolver<ChatQuickReplyChipThemeResolvers> = ({
32
+ themeTokens,
33
+ semanticTokens,
34
+ componentTokens,
35
+ }) => {
36
+ const resolve = (isActive?: boolean) => componentTokens.chat.quickReplyChip({
37
+ themeTokens,
38
+ semanticResolvers: semanticTokens,
39
+ config: { isActive },
40
+ })
41
+
42
+ return {
43
+ pressable: createValueResolver((state: ChatQuickReplyChipState) => {
44
+ const tokens = resolve(state.isActive)
45
+
46
+ const resolvePressable = (pressableState: PressableState) => componentTokens.pressable({
47
+ themeTokens,
48
+ semanticResolvers: semanticTokens,
49
+ overrides: {
50
+ size: tokens.config.size,
51
+ color: tokens.config.color,
52
+ coloringStyle: tokens.config.coloringStyle,
53
+ coloringColorVariant: tokens.config.coloringColorVariant,
54
+ hasAdditionalHorizontalPadding: tokens.config.hasAdditionalHorizontalPadding,
55
+ },
56
+ state: toPressableInteractionState(pressableState),
57
+ })
58
+
59
+ return {
60
+ container: createStyleResolver((pressableState: PressableState): PressableContainerStyle => ({
61
+ ...toContainerStyle(resolvePressable(pressableState).container),
62
+ ...toOptionalContainerStyle(tokens.container),
63
+ })),
64
+ stateLayer: createStyleResolver((pressableState: PressableState): PressableStateLayerStyle => ({
65
+ ...toContainerStyle(resolvePressable(pressableState).stateLayer),
66
+ position: 'absolute',
67
+ top: 0,
68
+ right: 0,
69
+ bottom: 0,
70
+ left: 0,
71
+ ...toOptionalContainerStyle(tokens.stateLayer),
72
+ })),
73
+ text: createStyleResolver((pressableState: PressableState): PressableTextStyle => ({
74
+ ...toTextStyle(resolvePressable(pressableState).text),
75
+ ...toOptionalTextStyle(tokens.text),
76
+ })),
77
+ }
78
+ }),
79
+ }
80
+ }
@@ -0,0 +1,41 @@
1
+ import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
2
+
3
+ import { toContainerStyle } from '../../adapters/container-adapter'
4
+ import { toIconStyle } from '../../adapters/icon-style-adapter'
5
+ import { toTextStyle } from '../../adapters/text-style-adapter'
6
+ import type {
7
+ ChatSystemLineIconStyle,
8
+ ChatSystemLineState,
9
+ ChatSystemLineStyle,
10
+ ChatSystemLineTextStyle,
11
+ ChatSystemLineThemeResolvers
12
+ } from '../../types/components/chat'
13
+ import {
14
+ createStyleResolver,
15
+ createValueResolver,
16
+ type ComponentThemeResolver
17
+ } from '../../types/resolver'
18
+
19
+ export const toChatSystemLineThemeResolvers: ComponentThemeResolver<ChatSystemLineThemeResolvers> = ({
20
+ themeTokens,
21
+ semanticTokens,
22
+ componentTokens,
23
+ }) => {
24
+ const resolve = (color?: ColorPairToken) => componentTokens.chat.systemLine({
25
+ themeTokens,
26
+ semanticResolvers: semanticTokens,
27
+ overrides: { color },
28
+ })
29
+
30
+ return {
31
+ container: createStyleResolver((state: ChatSystemLineState): ChatSystemLineStyle => (
32
+ toContainerStyle(resolve(state.color).container)
33
+ )),
34
+ text: createStyleResolver((state: ChatSystemLineState): ChatSystemLineTextStyle => (
35
+ toTextStyle(resolve(state.color).text)
36
+ )),
37
+ icon: createValueResolver((state: ChatSystemLineState): ChatSystemLineIconStyle => (
38
+ toIconStyle(resolve(state.color).icon)
39
+ )),
40
+ }
41
+ }
@@ -0,0 +1,85 @@
1
+ import type { AvatarTokens } from '@helpwave/hightide-design/component-token-resolvers'
2
+
3
+ import {
4
+ createAvatarStyleResolvers,
5
+ mergeAvatarTokens,
6
+ toDesignAvatarSize,
7
+ withNumericAvatarSize
8
+ } from '../avatar'
9
+ import { toContainerStyle } from '../../adapters/container-adapter'
10
+ import { toTextStyle } from '../../adapters/text-style-adapter'
11
+ import type {
12
+ ChatThreadHeaderContentRowStyle,
13
+ ChatThreadHeaderStyle,
14
+ ChatThreadHeaderSubtitleStyle,
15
+ ChatThreadHeaderThemeResolvers,
16
+ ChatThreadHeaderTitleStyle
17
+ } from '../../types/components/chat'
18
+ import type {
19
+ AvatarState,
20
+ AvatarThemeResolvers
21
+ } from '../../types/components/avatar'
22
+ import {
23
+ createSimpleStyleResolver,
24
+ createValueResolver,
25
+ type ComponentThemeResolver
26
+ } from '../../types/resolver'
27
+
28
+ export const toChatThreadHeaderThemeResolvers: ComponentThemeResolver<ChatThreadHeaderThemeResolvers> = ({
29
+ themeTokens,
30
+ semanticTokens,
31
+ componentTokens,
32
+ }) => {
33
+ const resolve = () => componentTokens.chat.threadHeader({
34
+ themeTokens,
35
+ semanticResolvers: semanticTokens,
36
+ })
37
+
38
+ return {
39
+ container: createSimpleStyleResolver((): ChatThreadHeaderStyle => (
40
+ toContainerStyle(resolve().container)
41
+ )),
42
+ contentRow: createSimpleStyleResolver((): ChatThreadHeaderContentRowStyle => ({
43
+ ...toContainerStyle(resolve().contentRow),
44
+ flex: 1,
45
+ })),
46
+ title: createSimpleStyleResolver((): ChatThreadHeaderTitleStyle => (
47
+ toTextStyle(resolve().title)
48
+ )),
49
+ subtitle: createSimpleStyleResolver((): ChatThreadHeaderSubtitleStyle => (
50
+ toTextStyle(resolve().subtitle)
51
+ )),
52
+ avatar: createValueResolver((state: AvatarState): AvatarThemeResolvers => {
53
+ const { avatarOverride } = resolve()
54
+
55
+ const resolveTokens = (avatarState: AvatarState): AvatarTokens => {
56
+ const tokens = mergeAvatarTokens(
57
+ componentTokens.avatar({
58
+ themeTokens,
59
+ semanticResolvers: semanticTokens,
60
+ config: {
61
+ isGrouped: avatarState.isGrouped,
62
+ groupIndex: avatarState.groupIndex,
63
+ },
64
+ overrides: {
65
+ color: avatarState.color ?? state.color ?? avatarOverride.overrides?.color,
66
+ size: toDesignAvatarSize(
67
+ avatarState.size ?? state.size ?? avatarOverride.overrides?.size
68
+ ),
69
+ },
70
+ }),
71
+ avatarOverride
72
+ )
73
+
74
+ const size = avatarState.size ?? state.size
75
+ if (typeof size === 'number') {
76
+ return withNumericAvatarSize(tokens, size)
77
+ }
78
+
79
+ return tokens
80
+ }
81
+
82
+ return createAvatarStyleResolvers(resolveTokens, themeTokens)
83
+ }),
84
+ }
85
+ }
@@ -1,91 +1,104 @@
1
- import type { ViewStyle } from 'react-native'
2
-
3
- import { componentLayouts } from '@helpwave/hightide-design/tokens'
4
1
  import type {
5
- ComponentColorTokens,
6
- HightideThemeTokens as DesignTokensTheme,
7
- ElementSize
8
- } from '@helpwave/hightide-design/types'
9
-
10
- import type { HightideSemanticColors } from '../types/color'
2
+ CheckboxState as DesignCheckboxState,
3
+ CheckboxStateValue
4
+ } from '@helpwave/hightide-design/component-token-resolvers'
5
+ import { toContainerStyle } from '../adapters/container-adapter'
6
+ import { toIconStyle } from '../adapters/icon-style-adapter'
11
7
  import type {
12
- CheckboxSize,
8
+ CheckboxIconStyle,
13
9
  CheckboxState,
14
- CheckboxTheme
10
+ CheckboxStateLayerStyle,
11
+ CheckboxStyle,
12
+ CheckboxThemeResolvers
15
13
  } from '../types/components/checkbox'
16
14
  import {
17
15
  createStyleResolver,
18
- createValueResolver
16
+ createValueResolver,
17
+ type ComponentThemeResolver
19
18
  } from '../types/resolver'
20
19
 
21
- const checkboxSizes: Record<CheckboxSize, number> = {
22
- sm: 20,
23
- md: 24,
24
- lg: 32,
25
- }
20
+ const toDesignCheckboxState = (state: CheckboxState): DesignCheckboxState => {
21
+ const active = new Set<CheckboxStateValue>()
26
22
 
27
- const checkboxIconSizes: Record<CheckboxSize, Exclude<ElementSize, 'xs'>> = {
28
- sm: 'sm',
29
- md: 'md',
30
- lg: 'lg',
31
- }
23
+ if (state.isDisabled) {
24
+ active.add('disabled')
25
+ }
26
+ if (state.isFocused) {
27
+ active.add('focused')
28
+ }
29
+ if (state.isFocusVisible) {
30
+ active.add('focusVisible')
31
+ }
32
+ if (state.isHovered) {
33
+ active.add('hovered')
34
+ }
35
+ if (state.isPressed) {
36
+ active.add('pressed')
37
+ }
38
+ if (state.isReadonly) {
39
+ active.add('readonly')
40
+ }
41
+ if (state.isInvalid) {
42
+ active.add('invalid')
43
+ }
44
+ if (state.isChecked) {
45
+ active.add('checked')
46
+ }
47
+ if (state.isIndeterminate) {
48
+ active.add('indeterminate')
49
+ }
32
50
 
33
- export type CreateCheckboxThemeOptions = {
34
- semantic: HightideSemanticColors,
35
- component: ComponentColorTokens,
51
+ return active
36
52
  }
37
53
 
38
- export const createCheckboxTheme = ({
39
- semantic,
40
- component,
41
- }: CreateCheckboxThemeOptions): CheckboxTheme => {
42
- const resolveState = (state: CheckboxState) => {
43
- const size = state.size ?? 'md'
44
- const dimension = checkboxSizes[size]
45
- const isActive = !!(state.isChecked || state.isIndeterminate)
46
- const showIndicator = !!(state.isIndeterminate || state.alwaysShowCheckIcon || state.isChecked)
47
-
48
- const borderColor = state.isDisabled
49
- ? semantic.disabled
50
- : state.isInvalid
51
- ? semantic.negative
52
- : (isActive ? semantic.primary : component.border)
54
+ const toNumberSize = (value: string | number | undefined): number => (
55
+ typeof value === 'number' ? value : 0
56
+ )
53
57
 
54
- const backgroundColor = state.isDisabled
55
- ? semantic.disabled
56
- : (isActive ? semantic.primary : component.input.background)
57
-
58
- const checkbox: ViewStyle = {
59
- width: dimension,
60
- height: dimension,
61
- alignItems: 'center',
62
- justifyContent: 'center',
63
- borderWidth: componentLayouts.shared.coloringOutlineWidth,
64
- borderColor,
65
- borderRadius: state.isRounded ? dimension / 2 : 6,
66
- backgroundColor,
67
- opacity: state.isDisabled ? 0.6 : 1,
68
- }
69
-
70
- return {
71
- checkbox,
72
- icon: {
73
- color: isActive ? semantic.onPrimary : semantic.primary,
74
- size: checkboxIconSizes[size],
75
- visible: showIndicator,
76
- },
77
- }
78
- }
58
+ export const toCheckboxThemeResolvers: ComponentThemeResolver<CheckboxThemeResolvers> = ({
59
+ themeTokens,
60
+ semanticTokens,
61
+ componentTokens,
62
+ }) => {
63
+ const resolve = (state: CheckboxState) => componentTokens.checkbox({
64
+ themeTokens,
65
+ semanticResolvers: semanticTokens,
66
+ overrides: {
67
+ size: state.size,
68
+ isRounded: state.isRounded,
69
+ color: state.color,
70
+ },
71
+ state: toDesignCheckboxState(state),
72
+ })
79
73
 
80
74
  return {
81
- checkbox: createStyleResolver((state) => resolveState(state).checkbox),
82
- icon: createValueResolver((state) => resolveState(state).icon),
83
- }
84
- }
75
+ container: createStyleResolver((state: CheckboxState): CheckboxStyle => (
76
+ toContainerStyle(resolve(state).container)
77
+ )),
78
+ stateLayer: createStyleResolver((state: CheckboxState): CheckboxStateLayerStyle => {
79
+ const tokens = resolve(state)
80
+ const containerStyle = toContainerStyle(tokens.container)
81
+ const touchTargetSize = semanticTokens.touchTargetSize({ themeTokens })
82
+ const width = toNumberSize(containerStyle.width as string | number | undefined)
83
+ const height = toNumberSize(containerStyle.height as string | number | undefined)
84
+ const horizontal = Math.max(0, touchTargetSize - width) / 2
85
+ const vertical = Math.max(0, touchTargetSize - height) / 2
85
86
 
86
- export const createCheckboxThemeFromDesign = (theme: DesignTokensTheme): CheckboxTheme => {
87
- return createCheckboxTheme({
88
- semantic: theme.semanticColors,
89
- component: theme.componentColors,
90
- })
87
+ return {
88
+ ...toContainerStyle(tokens.stateLayer),
89
+ position: 'absolute',
90
+ top: 0,
91
+ right: 0,
92
+ bottom: 0,
93
+ left: 0,
94
+ marginTop: -vertical,
95
+ marginRight: -horizontal,
96
+ marginBottom: -vertical,
97
+ marginLeft: -horizontal,
98
+ }
99
+ }),
100
+ icon: createValueResolver((state: CheckboxState): CheckboxIconStyle => (
101
+ toIconStyle(resolve(state).icon)
102
+ )),
103
+ }
91
104
  }
@@ -1,74 +1,37 @@
1
- import type {
2
- TextStyle,
3
- ViewStyle
4
- } from 'react-native'
5
-
6
- import {
7
- componentLayouts,
8
- fontWeights
9
- } from '@helpwave/hightide-design/tokens'
10
- import type { HightideThemeTokens as DesignTokensTheme } from '@helpwave/hightide-design/types'
11
-
12
- import { resolveColoringStyles } from './coloring'
13
- import type { HightideSemanticColors } from '../types/color'
1
+ import { toContainerStyle } from '../adapters/container-adapter'
2
+ import { toTextStyle } from '../adapters/text-style-adapter'
14
3
  import type {
15
4
  ChipState,
16
- ChipTheme
5
+ ChipStyle,
6
+ ChipTextStyle,
7
+ ChipThemeResolvers
17
8
  } from '../types/components/chip'
18
- import type { HightideComponentThemes } from '../types/components/hightide'
19
- import { createStyleResolver } from '../types/resolver'
20
-
21
- export type CreateChipThemeOptions = {
22
- semantic: HightideSemanticColors,
23
- coloring: HightideComponentThemes['coloring'],
24
- }
25
-
26
- export const createChipTheme = ({
27
- semantic,
28
- coloring,
29
- }: CreateChipThemeOptions): ChipTheme => {
30
- const resolveState = (state: ChipState) => {
31
- const size = state.size ?? 'md'
32
- const color = state.color ?? 'neutral'
33
- const coloringStyle = state.coloringStyle ?? 'solid'
34
- const tokens = coloring[color]
35
- const resolved = resolveColoringStyles(tokens, coloringStyle, semantic, state)
36
- const layout = componentLayouts.chip[size]
37
-
38
- const chip: ViewStyle = {
39
- flexDirection: 'row',
40
- alignItems: 'center',
41
- justifyContent: 'center',
42
- alignSelf: 'flex-start',
43
- backgroundColor: resolved.backgroundColor,
44
- borderColor: resolved.borderColor,
45
- borderWidth: resolved.borderWidth,
46
- paddingVertical: layout.paddingVertical,
47
- paddingHorizontal: layout.paddingHorizontal,
48
- gap: layout.gap,
49
- minHeight: layout.minHeight,
50
- borderRadius: layout.borderRadius,
51
- opacity: state.isDisabled ? 0.6 : 1,
52
- }
53
-
54
- const text: TextStyle = {
55
- color: resolved.color,
56
- fontSize: layout.fontSize,
57
- fontWeight: fontWeights.semibold,
58
- }
59
-
60
- return { chip, text }
61
- }
9
+ import {
10
+ createStyleResolver,
11
+ type ComponentThemeResolver
12
+ } from '../types/resolver'
13
+
14
+ export const toChipThemeResolvers: ComponentThemeResolver<ChipThemeResolvers> = ({
15
+ themeTokens,
16
+ semanticTokens,
17
+ componentTokens,
18
+ }) => {
19
+ const resolve = (state: ChipState) => componentTokens.chip({
20
+ themeTokens,
21
+ semanticResolvers: semanticTokens,
22
+ overrides: {
23
+ size: state.size,
24
+ color: state.color,
25
+ variant: state.variant,
26
+ },
27
+ })
62
28
 
63
29
  return {
64
- chip: createStyleResolver((state) => resolveState(state).chip),
65
- text: createStyleResolver((state) => resolveState(state).text),
30
+ chip: createStyleResolver((state: ChipState): ChipStyle => (
31
+ toContainerStyle(resolve(state).container)
32
+ )),
33
+ text: createStyleResolver((state: ChipState): ChipTextStyle => (
34
+ toTextStyle(resolve(state).text)
35
+ )),
66
36
  }
67
37
  }
68
-
69
- export const createChipThemeFromDesign = (theme: DesignTokensTheme): ChipTheme => {
70
- return createChipTheme({
71
- semantic: theme.semanticColors,
72
- coloring: theme.coloring as HightideComponentThemes['coloring'],
73
- })
74
- }
@@ -0,0 +1,136 @@
1
+ import { buttonVariants } from '@helpwave/hightide-design/component-token-resolvers'
2
+ import type {
3
+ ButtonVariant } from '@helpwave/hightide-design/semantic-token-resolvers'
4
+ import {
5
+ mapButtonVariant,
6
+ resolveColoringColorVariant,
7
+ resolveColoringStyle,
8
+ resolvePressableColoring
9
+ } from '@helpwave/hightide-design/semantic-token-resolvers'
10
+ import type {
11
+ ColorPairToken,
12
+ ThemeTokens
13
+ } from '@helpwave/hightide-design/theme-tokens'
14
+
15
+ import type { Color } from '../types/color'
16
+ import {
17
+ toPressableInteractionState,
18
+ type InteractionState
19
+ } from '../types/resolver'
20
+
21
+ const colorSchemeKeys = [
22
+ 'primary',
23
+ 'secondary',
24
+ 'tertiary',
25
+ 'positive',
26
+ 'warning',
27
+ 'negative',
28
+ 'neutral',
29
+ ] as const
30
+
31
+ export type ResolvedColoringStyles = {
32
+ backgroundColor: Color,
33
+ color: Color,
34
+ borderColor?: Color,
35
+ }
36
+
37
+ export type ColoringState = {
38
+ color: Color,
39
+ foreground: Color,
40
+ border: Color,
41
+ }
42
+
43
+ export type ColoringStateProperty = {
44
+ base: ColoringState,
45
+ emphasisOverride: ColoringState,
46
+ }
47
+
48
+ export type HightideColorScheme = Record<ButtonVariant, ColoringStateProperty>
49
+
50
+ export type HightideColorSchemes = {
51
+ primary: HightideColorScheme,
52
+ secondary: HightideColorScheme,
53
+ tertiary: HightideColorScheme,
54
+ positive: HightideColorScheme,
55
+ warning: HightideColorScheme,
56
+ negative: HightideColorScheme,
57
+ neutral: HightideColorScheme,
58
+ disabled: HightideColorScheme,
59
+ }
60
+
61
+ export const resolveColoringStyles = (
62
+ themeTokens: ThemeTokens,
63
+ colorPair: ColorPairToken,
64
+ variant: ButtonVariant,
65
+ state: InteractionState = {}
66
+ ): ResolvedColoringStyles => {
67
+ const { colorVariant, style } = mapButtonVariant(variant)
68
+ const coloring = resolveColoringStyle({
69
+ themeTokens,
70
+ coloring: resolveColoringColorVariant({
71
+ themeTokens,
72
+ colorPair,
73
+ variant: colorVariant,
74
+ }),
75
+ style,
76
+ })
77
+ const resolved = resolvePressableColoring({
78
+ themeTokens,
79
+ coloring,
80
+ variant,
81
+ state: toPressableInteractionState(state),
82
+ })
83
+
84
+ return {
85
+ backgroundColor: resolved.background,
86
+ color: resolved.foreground,
87
+ borderColor: resolved.border !== 'transparent'
88
+ ? resolved.border
89
+ : resolved.outline !== 'transparent'
90
+ ? resolved.outline
91
+ : resolved.background,
92
+ }
93
+ }
94
+
95
+ const toColoringState = (
96
+ themeTokens: ThemeTokens,
97
+ colorPair: ColorPairToken,
98
+ variant: ButtonVariant,
99
+ state: InteractionState
100
+ ): ColoringState => {
101
+ const resolved = resolveColoringStyles(themeTokens, colorPair, variant, state)
102
+
103
+ return {
104
+ color: resolved.backgroundColor,
105
+ foreground: resolved.color,
106
+ border: resolved.borderColor ?? resolved.backgroundColor,
107
+ }
108
+ }
109
+
110
+ export const createColorSchemes = (themeTokens: ThemeTokens): HightideColorSchemes => (
111
+ Object.fromEntries(
112
+ colorSchemeKeys.map((key) => [
113
+ key,
114
+ Object.fromEntries(
115
+ buttonVariants.map((variant) => [
116
+ variant,
117
+ {
118
+ base: toColoringState(themeTokens, themeTokens.color[key], variant, {}),
119
+ emphasisOverride: toColoringState(
120
+ themeTokens,
121
+ themeTokens.color[key],
122
+ variant,
123
+ { isHovered: true }
124
+ ),
125
+ } satisfies ColoringStateProperty,
126
+ ])
127
+ ),
128
+ ])
129
+ ) as HightideColorSchemes
130
+ )
131
+
132
+ export const isOutlinedVariant = (
133
+ variant: ButtonVariant
134
+ ): boolean => {
135
+ return variant === 'outlined'
136
+ }
@@ -0,0 +1,34 @@
1
+ import { toContainerStyle } from '../adapters/container-adapter'
2
+ import type {
3
+ DividerState,
4
+ DividerStyle,
5
+ DividerThemeResolvers
6
+ } from '../types/components/divider'
7
+ import {
8
+ createStyleResolver,
9
+ type ComponentThemeResolver
10
+ } from '../types/resolver'
11
+
12
+ export const toDividerThemeResolvers: ComponentThemeResolver<DividerThemeResolvers> = ({
13
+ themeTokens,
14
+ semanticTokens,
15
+ componentTokens,
16
+ }) => {
17
+ const resolve = (state: DividerState = {}) => componentTokens.divider({
18
+ themeTokens,
19
+ semanticResolvers: semanticTokens,
20
+ overrides: {
21
+ direction: state.direction,
22
+ color: state.color,
23
+ width: state.width,
24
+ margin: state.margin,
25
+ },
26
+ })
27
+
28
+ return {
29
+ container: createStyleResolver((state: DividerState): DividerStyle => ({
30
+ ...toContainerStyle(resolve(state)),
31
+ alignSelf: 'stretch',
32
+ })),
33
+ }
34
+ }
@@ -0,0 +1,21 @@
1
+ import { iconSizes } from '@helpwave/hightide-design/theme-tokens'
2
+
3
+ import type { IconThemeResolvers } from '../types/components/hightide'
4
+ import type { ComponentThemeResolver } from '../types/resolver'
5
+
6
+ export const toIconThemeResolvers: ComponentThemeResolver<IconThemeResolvers> = ({
7
+ themeTokens,
8
+ semanticTokens,
9
+ componentTokens,
10
+ }) => (
11
+ Object.fromEntries(
12
+ iconSizes.map((size) => [
13
+ size,
14
+ componentTokens.icon({
15
+ themeTokens,
16
+ semanticResolvers: semanticTokens,
17
+ overrides: { size },
18
+ }),
19
+ ])
20
+ ) as IconThemeResolvers
21
+ )