@korsolutions/ui 0.0.90 → 0.0.92

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 (108) hide show
  1. package/dist/module/components/avatar/components/avatar-image.js.map +1 -1
  2. package/dist/module/components/badge/badge.js +1 -6
  3. package/dist/module/components/badge/badge.js.map +1 -1
  4. package/dist/module/components/badge/variants/default.js +3 -2
  5. package/dist/module/components/badge/variants/default.js.map +1 -1
  6. package/dist/module/components/badge/variants/secondary.js +2 -1
  7. package/dist/module/components/badge/variants/secondary.js.map +1 -1
  8. package/dist/module/components/card/card-title.js +2 -3
  9. package/dist/module/components/card/card-title.js.map +1 -1
  10. package/dist/module/components/combobox/components/combobox-list.js +24 -0
  11. package/dist/module/components/combobox/components/combobox-list.js.map +1 -0
  12. package/dist/module/components/combobox/components/combobox-option.js +17 -25
  13. package/dist/module/components/combobox/components/combobox-option.js.map +1 -1
  14. package/dist/module/components/combobox/components/combobox-overlay.js +0 -1
  15. package/dist/module/components/combobox/components/combobox-overlay.js.map +1 -1
  16. package/dist/module/components/combobox/components/combobox-root.js +62 -11
  17. package/dist/module/components/combobox/components/combobox-root.js.map +1 -1
  18. package/dist/module/components/combobox/components/combobox-trigger.js +32 -18
  19. package/dist/module/components/combobox/components/combobox-trigger.js.map +1 -1
  20. package/dist/module/components/combobox/context.js.map +1 -1
  21. package/dist/module/components/combobox/index.js +2 -0
  22. package/dist/module/components/combobox/index.js.map +1 -1
  23. package/dist/module/components/link/link.js +16 -6
  24. package/dist/module/components/link/link.js.map +1 -1
  25. package/dist/module/components/menu/components/menu-selection-indicator.js +4 -3
  26. package/dist/module/components/menu/components/menu-selection-indicator.js.map +1 -1
  27. package/dist/module/components/phone-input/components/phone-input.js +16 -7
  28. package/dist/module/components/phone-input/components/phone-input.js.map +1 -1
  29. package/dist/module/components/portal/portal.js.map +1 -1
  30. package/dist/module/components/select/components/select-option.js +13 -16
  31. package/dist/module/components/select/components/select-option.js.map +1 -1
  32. package/dist/module/components/select/components/select-trigger.js +3 -1
  33. package/dist/module/components/select/components/select-trigger.js.map +1 -1
  34. package/dist/module/components/select/variants/default.js +6 -3
  35. package/dist/module/components/select/variants/default.js.map +1 -1
  36. package/dist/module/hooks/use-relative-position.js.map +1 -1
  37. package/dist/module/utils/normalize-layout.js.map +1 -1
  38. package/dist/typescript/src/components/avatar/components/avatar-image.d.ts +2 -2
  39. package/dist/typescript/src/components/avatar/components/avatar-image.d.ts.map +1 -1
  40. package/dist/typescript/src/components/badge/badge.d.ts.map +1 -1
  41. package/dist/typescript/src/components/badge/variants/default.d.ts.map +1 -1
  42. package/dist/typescript/src/components/badge/variants/secondary.d.ts.map +1 -1
  43. package/dist/typescript/src/components/card/card-title.d.ts +2 -2
  44. package/dist/typescript/src/components/card/card-title.d.ts.map +1 -1
  45. package/dist/typescript/src/components/combobox/components/combobox-list.d.ts +12 -0
  46. package/dist/typescript/src/components/combobox/components/combobox-list.d.ts.map +1 -0
  47. package/dist/typescript/src/components/combobox/components/combobox-option.d.ts +5 -5
  48. package/dist/typescript/src/components/combobox/components/combobox-option.d.ts.map +1 -1
  49. package/dist/typescript/src/components/combobox/components/combobox-overlay.d.ts.map +1 -1
  50. package/dist/typescript/src/components/combobox/components/combobox-root.d.ts +26 -6
  51. package/dist/typescript/src/components/combobox/components/combobox-root.d.ts.map +1 -1
  52. package/dist/typescript/src/components/combobox/components/combobox-trigger.d.ts +13 -4
  53. package/dist/typescript/src/components/combobox/components/combobox-trigger.d.ts.map +1 -1
  54. package/dist/typescript/src/components/combobox/context.d.ts +6 -2
  55. package/dist/typescript/src/components/combobox/context.d.ts.map +1 -1
  56. package/dist/typescript/src/components/combobox/index.d.ts +3 -0
  57. package/dist/typescript/src/components/combobox/index.d.ts.map +1 -1
  58. package/dist/typescript/src/components/combobox/types.d.ts +2 -3
  59. package/dist/typescript/src/components/combobox/types.d.ts.map +1 -1
  60. package/dist/typescript/src/components/input/input.d.ts +1 -1
  61. package/dist/typescript/src/components/input/input.d.ts.map +1 -1
  62. package/dist/typescript/src/components/link/link.d.ts +9 -3
  63. package/dist/typescript/src/components/link/link.d.ts.map +1 -1
  64. package/dist/typescript/src/components/menu/components/menu-selection-indicator.d.ts.map +1 -1
  65. package/dist/typescript/src/components/phone-input/components/phone-input.d.ts +4 -6
  66. package/dist/typescript/src/components/phone-input/components/phone-input.d.ts.map +1 -1
  67. package/dist/typescript/src/components/phone-input/index.d.ts +1 -2
  68. package/dist/typescript/src/components/phone-input/index.d.ts.map +1 -1
  69. package/dist/typescript/src/components/select/components/select-option.d.ts +4 -1
  70. package/dist/typescript/src/components/select/components/select-option.d.ts.map +1 -1
  71. package/dist/typescript/src/components/select/components/select-trigger.d.ts.map +1 -1
  72. package/dist/typescript/src/components/select/variants/default.d.ts.map +1 -1
  73. package/dist/typescript/src/hooks/use-relative-position.d.ts +2 -2
  74. package/dist/typescript/src/hooks/use-relative-position.d.ts.map +1 -1
  75. package/dist/typescript/src/themes/types.d.ts +4 -0
  76. package/dist/typescript/src/themes/types.d.ts.map +1 -1
  77. package/dist/typescript/src/types/element.types.d.ts +3 -10
  78. package/dist/typescript/src/types/element.types.d.ts.map +1 -1
  79. package/dist/typescript/src/types/props.types.d.ts +1 -1
  80. package/dist/typescript/src/types/props.types.d.ts.map +1 -1
  81. package/dist/typescript/src/utils/normalize-layout.d.ts +3 -2
  82. package/dist/typescript/src/utils/normalize-layout.d.ts.map +1 -1
  83. package/package.json +1 -1
  84. package/src/components/avatar/components/avatar-image.tsx +2 -2
  85. package/src/components/badge/badge.tsx +1 -3
  86. package/src/components/badge/variants/default.tsx +2 -1
  87. package/src/components/badge/variants/secondary.tsx +1 -0
  88. package/src/components/card/card-title.tsx +7 -4
  89. package/src/components/combobox/components/combobox-list.tsx +32 -0
  90. package/src/components/combobox/components/combobox-option.tsx +25 -36
  91. package/src/components/combobox/components/combobox-overlay.tsx +0 -1
  92. package/src/components/combobox/components/combobox-root.tsx +110 -23
  93. package/src/components/combobox/components/combobox-trigger.tsx +44 -21
  94. package/src/components/combobox/context.ts +7 -2
  95. package/src/components/combobox/index.ts +3 -0
  96. package/src/components/combobox/types.ts +2 -3
  97. package/src/components/link/link.tsx +24 -8
  98. package/src/components/menu/components/menu-selection-indicator.tsx +5 -4
  99. package/src/components/phone-input/components/phone-input.tsx +33 -23
  100. package/src/components/portal/portal.tsx +2 -2
  101. package/src/components/select/components/select-option.tsx +23 -19
  102. package/src/components/select/components/select-trigger.tsx +11 -6
  103. package/src/components/select/variants/default.tsx +4 -0
  104. package/src/hooks/use-relative-position.ts +4 -4
  105. package/src/themes/types.ts +4 -0
  106. package/src/types/element.types.ts +3 -10
  107. package/src/types/props.types.ts +1 -1
  108. package/src/utils/normalize-layout.ts +3 -2
@@ -6,9 +6,17 @@ import { measureLayoutPosition } from "../../../utils/normalize-layout";
6
6
  import { useCombobox } from "../context";
7
7
  import type { ComboboxTriggerState } from "../types";
8
8
 
9
- export interface ComboboxTriggerProps {
10
- placeholder?: string;
11
- }
9
+ type ExtendableProps = Omit<TextInputProps, "value" | "onChange" | "onChangeText">;
10
+
11
+ type RenderProps = {
12
+ inputRef: React.RefObject<TextInputRef | null>;
13
+ open: () => void;
14
+ setInputValue: (value: string) => void;
15
+ };
16
+
17
+ export type ComboboxTriggerProps = ExtendableProps & {
18
+ render?: (props: RenderProps) => React.ReactNode;
19
+ };
12
20
 
13
21
  const calculateState = (isDisabled: boolean, isOpen: boolean): ComboboxTriggerState => {
14
22
  if (isDisabled) return "disabled";
@@ -16,17 +24,17 @@ const calculateState = (isDisabled: boolean, isOpen: boolean): ComboboxTriggerSt
16
24
  return "default";
17
25
  };
18
26
 
19
- export function ComboboxTrigger(props: ComboboxTriggerProps) {
27
+ export function ComboboxTrigger({ render, ...props }: ComboboxTriggerProps) {
20
28
  const combobox = useCombobox();
21
29
  const triggerRef = useRef<TextInputRef>(null);
22
30
 
23
31
  const triggerState = calculateState(combobox.isDisabled, combobox.isOpen);
24
-
25
- const displayValue = combobox.isOpen ? combobox.inputValue : (combobox.value ?? "");
32
+ const selectedLabel = combobox.value != null ? combobox.getItemLabel(combobox.value) : "";
33
+ const displayValue = combobox.isOpen ? combobox.inputValue : selectedLabel;
26
34
 
27
35
  const open = () => {
28
36
  if (combobox.isDisabled) return;
29
- combobox.setInputValue(combobox.value ?? "");
37
+ combobox.setInputValue(selectedLabel);
30
38
  requestAnimationFrame(() => {
31
39
  measureLayoutPosition(triggerRef.current, (layout) => {
32
40
  combobox.setTriggerPosition(layout);
@@ -35,9 +43,25 @@ export function ComboboxTrigger(props: ComboboxTriggerProps) {
35
43
  });
36
44
  };
37
45
 
46
+ const onChangeText = (text: string) => {
47
+ if (combobox.isDisabled) return;
48
+ combobox.setInputValue(text);
49
+ if (!combobox.isOpen) open();
50
+ };
51
+
52
+ const onFocus = () => {
53
+ if (!combobox.isOpen) open();
54
+ };
55
+
56
+ const setInputValue = (value: string) => {
57
+ combobox.setInputValue(value);
58
+ if (triggerRef.current) {
59
+ setInnerInputValue(triggerRef.current, value);
60
+ }
61
+ };
62
+
38
63
  useEffect(() => {
39
- if (!triggerRef.current) return;
40
- setInnerInputValue(triggerRef.current, displayValue);
64
+ setInputValue(displayValue);
41
65
  }, [displayValue]);
42
66
 
43
67
  useEffect(() => {
@@ -60,26 +84,25 @@ export function ComboboxTrigger(props: ComboboxTriggerProps) {
60
84
  const composedStyle = StyleSheet.flatten([
61
85
  triggerStyles?.default?.style,
62
86
  triggerStyles?.[triggerState]?.style,
87
+ props.style,
63
88
  ]);
64
89
 
90
+ if (render) {
91
+ return render({
92
+ inputRef: triggerRef,
93
+ open,
94
+ setInputValue,
95
+ });
96
+ }
97
+
65
98
  return (
66
99
  <TextInput
67
100
  {...composedProps}
68
101
  ref={triggerRef}
69
102
  value={undefined}
70
103
  onChange={undefined}
71
- onChangeText={(text) => {
72
- if (combobox.isDisabled) return;
73
- combobox.setInputValue(text);
74
- if (!combobox.isOpen) {
75
- open();
76
- }
77
- }}
78
- onFocus={() => {
79
- if (!combobox.isOpen) {
80
- open();
81
- }
82
- }}
104
+ onChangeText={onChangeText}
105
+ onFocus={onFocus}
83
106
  style={composedStyle}
84
107
  />
85
108
  );
@@ -4,8 +4,13 @@ import type { LayoutPosition } from "../../hooks";
4
4
  import type { ComboboxState, ComboboxStyles } from "./types";
5
5
 
6
6
  export interface ComboboxContext {
7
- value?: string;
8
- onChange?: (value: string) => void;
7
+ items: readonly unknown[];
8
+ filteredItems: readonly unknown[];
9
+ getItemValue: (item: unknown) => string;
10
+ getItemLabel: (item: unknown) => string;
11
+
12
+ value: unknown | undefined;
13
+ onChange: ((item: unknown) => void) | undefined;
9
14
 
10
15
  isOpen: boolean;
11
16
  setIsOpen: Dispatch<React.SetStateAction<boolean>>;
@@ -1,5 +1,6 @@
1
1
  import { ComboboxContent } from "./components/combobox-content";
2
2
  import { ComboboxEmpty } from "./components/combobox-empty";
3
+ import { ComboboxList } from "./components/combobox-list";
3
4
  import { ComboboxOption } from "./components/combobox-option";
4
5
  import { ComboboxOverlay } from "./components/combobox-overlay";
5
6
  import { ComboboxPortal } from "./components/combobox-portal";
@@ -12,12 +13,14 @@ export const Combobox = {
12
13
  Portal: ComboboxPortal,
13
14
  Overlay: ComboboxOverlay,
14
15
  Content: ComboboxContent,
16
+ List: ComboboxList,
15
17
  Option: ComboboxOption,
16
18
  Empty: ComboboxEmpty,
17
19
  };
18
20
 
19
21
  export type { ComboboxContentProps } from "./components/combobox-content";
20
22
  export type { ComboboxEmptyProps } from "./components/combobox-empty";
23
+ export type { ComboboxListProps } from "./components/combobox-list";
21
24
  export type { ComboboxOptionProps } from "./components/combobox-option";
22
25
  export type { ComboboxOverlayProps } from "./components/combobox-overlay";
23
26
  export type { ComboboxPortalProps } from "./components/combobox-portal";
@@ -1,14 +1,13 @@
1
- import type { TextInputProps, TextStyle } from "react-native";
1
+ import type { StyleProp, TextInputProps, TextStyle, ViewStyle } from "react-native";
2
2
  import type { ComboboxContentProps } from "./components/combobox-content";
3
3
  import type { ComboboxOverlayProps } from "./components/combobox-overlay";
4
- import type { ComboboxRootProps } from "./components/combobox-root";
5
4
 
6
5
  export type ComboboxState = "default" | "disabled";
7
6
  export type ComboboxTriggerState = ComboboxState | "focused";
8
7
  export type ComboboxOptionState = ComboboxState | "hovered" | "selected";
9
8
 
10
9
  export interface ComboboxStyles {
11
- root?: Partial<Record<ComboboxState, ComboboxRootProps["style"]>>;
10
+ root?: Partial<Record<ComboboxState, StyleProp<ViewStyle>>>;
12
11
  trigger?: Partial<Record<ComboboxTriggerState, TextInputProps>>;
13
12
  overlay?: Partial<Record<ComboboxState, ComboboxOverlayProps["style"]>>;
14
13
  content?: Partial<Record<ComboboxState, ComboboxContentProps["style"]>>;
@@ -1,26 +1,42 @@
1
1
  import React from "react";
2
- import { Linking, Text as RnText, type TextProps as RnTextProps } from "react-native";
2
+ import { Linking, Text as RnText, StyleSheet, type TextProps as RnTextProps } from "react-native";
3
+ import { useComponentConfig } from "../../themes/provider";
3
4
  import { LinkVariants } from "./variants";
4
5
 
5
- export interface LinkProps extends RnTextProps {
6
- href?: string;
6
+ export type ExtendableProps = Omit<RnTextProps, "onPress" | "style">;
7
7
 
8
+ export type LinkStyles = RnTextProps["style"];
9
+
10
+ export type LinkProps = RnTextProps & {
8
11
  variant?: keyof typeof LinkVariants;
9
- }
12
+ style?: LinkStyles;
13
+ } & (
14
+ | {
15
+ href?: string;
16
+ }
17
+ | {
18
+ onPress?: RnTextProps["onPress"];
19
+ }
20
+ );
10
21
 
11
22
  export function Link(props: LinkProps) {
12
- const useVariantStyles = LinkVariants[props.variant ?? "default"];
23
+ const { style, onPress, variant = "default", ...rest } = props;
24
+ const useVariantStyles = LinkVariants[variant];
25
+ const config = useComponentConfig("link");
13
26
  const variantStyles = useVariantStyles();
14
27
 
15
28
  const handlePress: RnTextProps["onPress"] = async (e) => {
16
- if (props.href) {
29
+ if ("href" in props && props.href) {
17
30
  const supported = await Linking.canOpenURL(props.href);
18
31
  if (supported) {
19
32
  await Linking.openURL(props.href);
20
33
  }
34
+ } else {
35
+ onPress?.(e);
21
36
  }
22
- props.onPress?.(e);
23
37
  };
24
38
 
25
- return <RnText {...props} style={variantStyles} onPress={handlePress} />;
39
+ const composedStyles = StyleSheet.flatten([variantStyles, config?.styles, style]);
40
+
41
+ return <RnText {...rest} style={composedStyles} onPress={handlePress} />;
26
42
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Text, View } from "react-native";
2
+ import { Text, View, type StyleProp, type ViewStyle } from "react-native";
3
3
  import { useComponentConfig } from "../../../themes/provider";
4
4
  import { useMenu } from "../context";
5
5
 
@@ -11,14 +11,15 @@ export function MenuSelectionIndicator({ isSelected }: MenuSelectionIndicatorPro
11
11
  const config = useComponentConfig("menu");
12
12
  const menu = useMenu();
13
13
  const SelectionIcon = config?.selectionIcon;
14
+ const indicatorStyles = menu.styles?.selectionIndicator;
14
15
 
15
16
  if (!isSelected) {
16
- return <View style={menu.styles?.selectionIndicator} />;
17
+ return <View style={indicatorStyles as StyleProp<ViewStyle>} />;
17
18
  }
18
19
 
19
20
  if (SelectionIcon) {
20
- return <SelectionIcon {...menu.styles?.selectionIndicator} />;
21
+ return <SelectionIcon {...indicatorStyles} />;
21
22
  }
22
23
 
23
- return <Text style={menu.styles?.selectionIndicator}>✓</Text>;
24
+ return <Text style={indicatorStyles}>✓</Text>;
24
25
  }
@@ -1,28 +1,38 @@
1
- import React from "react";
2
- import { type StyleProp, StyleSheet, TextInput, type TextStyle } from "react-native";
1
+ import React, { forwardRef } from "react";
2
+ import { StyleSheet, TextInput, type TextInputProps } from "react-native";
3
+ import type { TextInputRef } from "../../../types/element.types";
3
4
  import { usePhoneInput } from "../context";
4
5
 
5
- export interface PhoneInputProps {
6
- placeholder?: string;
7
- style?: StyleProp<TextStyle>;
8
- }
6
+ export type ExpandableProps = Omit<TextInputProps, "value" | "onChangeText">;
9
7
 
10
- export function PhoneInput({ placeholder = "Enter phone number", style }: PhoneInputProps) {
11
- const { styles, state, setIsFocused, phoneMask, isDisabled } = usePhoneInput();
8
+ export type PhoneInputProps = ExpandableProps;
12
9
 
13
- const inputStyles = StyleSheet.flatten([styles.input?.default, styles.input?.[state], style]);
10
+ export const PhoneInput = forwardRef<TextInputRef, PhoneInputProps>(
11
+ ({ placeholder = "Enter phone number", style, ...props }, ref) => {
12
+ const { styles, state, setIsFocused, phoneMask, isDisabled } = usePhoneInput();
14
13
 
15
- return (
16
- <TextInput
17
- value={phoneMask.displayValue}
18
- onChangeText={phoneMask.onChangeText}
19
- keyboardType={phoneMask.keyboardType}
20
- placeholder={placeholder}
21
- placeholderTextColor={StyleSheet.flatten(styles.countryButtonText?.disabled)?.color}
22
- readOnly={isDisabled}
23
- onFocus={() => setIsFocused(true)}
24
- onBlur={() => setIsFocused(false)}
25
- style={inputStyles}
26
- />
27
- );
28
- }
14
+ const inputStyles = StyleSheet.flatten([styles.input?.default, styles.input?.[state], style]);
15
+
16
+ return (
17
+ <TextInput
18
+ {...props}
19
+ ref={ref}
20
+ value={phoneMask.displayValue}
21
+ onChangeText={phoneMask.onChangeText}
22
+ keyboardType={phoneMask.keyboardType}
23
+ placeholder={placeholder}
24
+ placeholderTextColor={StyleSheet.flatten(styles.countryButtonText?.disabled)?.color}
25
+ readOnly={isDisabled}
26
+ onFocus={(e) => {
27
+ setIsFocused(true);
28
+ props.onFocus?.(e);
29
+ }}
30
+ onBlur={(e) => {
31
+ setIsFocused(false);
32
+ props.onBlur?.(e);
33
+ }}
34
+ style={inputStyles}
35
+ />
36
+ );
37
+ },
38
+ );
@@ -6,7 +6,7 @@ import React, {
6
6
  useState,
7
7
  useSyncExternalStore,
8
8
  } from "react";
9
- import { Platform, View, type HostInstance } from "react-native";
9
+ import { Platform, View } from "react-native";
10
10
  import { measureLayoutPosition } from "../../utils/normalize-layout";
11
11
  import { PortalOffsetContext, type PortalOffset } from "./portal-offset";
12
12
  import { DEFAULT_PORTAL_HOST, type PortalHostProps, type PortalProps } from "./portal.constants";
@@ -58,7 +58,7 @@ function removePortal(hostName: string, name: string) {
58
58
  }
59
59
 
60
60
  function DefaultContainer(props: React.PropsWithChildren) {
61
- const containerRef = useRef<HostInstance>(null);
61
+ const containerRef = useRef<React.ComponentRef<typeof View>>(null);
62
62
  const [offset, setOffset] = useState<PortalOffset | null>(null);
63
63
 
64
64
  const onLayout = useCallback(() => {
@@ -1,12 +1,13 @@
1
- import { calculateComposedStyles } from "../../../utils/calculate-styles";
2
1
  import React, { useEffect, useState } from "react";
3
- import { Pressable, Text } from "react-native";
2
+ import { Pressable, StyleSheet, type PressableProps } from "react-native";
3
+ import type { ElementChildren } from "../../../types/element.types";
4
4
  import { useSelect } from "../context";
5
5
  import type { SelectOptionState, SelectState } from "../types";
6
6
 
7
7
  export type SelectOptionProps = {
8
8
  value: string;
9
- children?: React.ReactNode;
9
+ children?: ElementChildren;
10
+ style?: PressableProps["style"];
10
11
  };
11
12
 
12
13
  const calculateState = (
@@ -32,8 +33,7 @@ export function SelectOption(props: SelectOptionProps): React.ReactElement {
32
33
  const isSelected = select.value === props.value;
33
34
 
34
35
  const optionState = calculateState(select.state, isHovered, isSelected);
35
- const composedStyles = calculateComposedStyles(select.styles, optionState, "option");
36
-
36
+ const optionStyles = select.styles?.option;
37
37
  useEffect(() => {
38
38
  select.setOptions((prev) => {
39
39
  if (prev.find((option) => option.value === props.value)) {
@@ -43,23 +43,27 @@ export function SelectOption(props: SelectOptionProps): React.ReactElement {
43
43
  });
44
44
  }, [props.value, props.children]);
45
45
 
46
- const Component = typeof props.children === "string" ? Text : Pressable;
46
+ const handlePress = () => {
47
+ select.onChange?.(props.value);
48
+ select.setIsOpen(false);
49
+ };
50
+ const handlePointerEnter = () => setIsHovered(true);
51
+ const handlePointerLeave = () => setIsHovered(false);
47
52
 
48
53
  return (
49
- <Component
50
- onPress={() => {
51
- select.onChange?.(props.value);
52
- select.setIsOpen(false);
53
- }}
54
- onPointerEnter={() => {
55
- setIsHovered(true);
56
- }}
57
- onPointerLeave={() => {
58
- setIsHovered(false);
59
- }}
60
- style={composedStyles}
54
+ <Pressable
55
+ onPress={handlePress}
56
+ onPointerEnter={handlePointerEnter}
57
+ onPointerLeave={handlePointerLeave}
58
+ style={(styleProps) =>
59
+ StyleSheet.flatten([
60
+ optionStyles?.default,
61
+ optionStyles?.[optionState],
62
+ typeof props.style === "function" ? props.style(styleProps) : props.style,
63
+ ])
64
+ }
61
65
  >
62
66
  {props.children}
63
- </Component>
67
+ </Pressable>
64
68
  );
65
69
  }
@@ -1,5 +1,11 @@
1
1
  import React, { useRef } from "react";
2
- import { Pressable, Text, type StyleProp, type TextStyle, type ViewStyle } from "react-native";
2
+ import {
3
+ Pressable,
4
+ Text,
5
+ type StyleProp,
6
+ type TextStyle,
7
+ type ViewStyle,
8
+ } from "react-native";
3
9
  import type { ViewRef } from "../../../types/element.types";
4
10
  import { calculateComposedStyles } from "../../../utils/calculate-styles";
5
11
  import { measureLayoutPosition } from "../../../utils/normalize-layout";
@@ -56,11 +62,10 @@ export function SelectValue(props: SelectValueProps) {
56
62
  const selectedOptionLabel = selectedOption?.label;
57
63
  const displayValue = selectedOptionLabel ?? select.value;
58
64
 
59
- const composedStyles = calculateComposedStyles(
60
- select.styles,
61
- select.state,
62
- displayValue ? "value" : "placeholder",
63
- );
65
+ const key = displayValue ? "value" : "placeholder";
66
+ const slotStyles = select.styles?.[key];
67
+ const composedStyles: StyleProp<TextStyle> = [slotStyles?.default, slotStyles?.[select.state]];
68
+
64
69
  if (!!displayValue && typeof displayValue !== "string") {
65
70
  return <>{displayValue}</>;
66
71
  }
@@ -1,3 +1,4 @@
1
+ import type { CursorValue } from "react-native";
1
2
  import type { Size } from "../../../utils/size-scale";
2
3
  import { useThemedStyles } from "../../../utils/use-themed-styles";
3
4
  import { type SelectStyles } from "../types";
@@ -23,6 +24,7 @@ export function useSelectVariantDefault(size: Size): SelectStyles {
23
24
  },
24
25
  disabled: {
25
26
  backgroundColor: colors.muted,
27
+ cursor: "not-allowed" as CursorValue,
26
28
  },
27
29
  },
28
30
  value: {
@@ -74,9 +76,11 @@ export function useSelectVariantDefault(size: Size): SelectStyles {
74
76
  lineHeight: s.lineHeight,
75
77
  color: colors.foreground,
76
78
  borderRadius: radius / 2,
79
+ cursor: "pointer",
77
80
  },
78
81
  disabled: {
79
82
  color: colors.mutedForeground,
83
+ cursor: "not-allowed" as CursorValue,
80
84
  },
81
85
  selected: {
82
86
  backgroundColor: colors.muted,
@@ -2,8 +2,8 @@ import { useMemo } from "react";
2
2
  import {
3
3
  Platform,
4
4
  useWindowDimensions,
5
- type DisplayMetrics,
6
5
  type LayoutRectangle,
6
+ type ScaledSize,
7
7
  type ViewStyle,
8
8
  } from "react-native";
9
9
  import { usePortalOffset } from "../components/portal";
@@ -118,7 +118,7 @@ export interface LayoutPosition {
118
118
  }
119
119
 
120
120
  interface GetPositionArgs {
121
- dimensions: DisplayMetrics;
121
+ dimensions: ScaledSize;
122
122
  triggerPosition: LayoutPosition;
123
123
  contentLayout: LayoutRectangle;
124
124
  insets: SafeAreaInsets;
@@ -148,7 +148,7 @@ interface GetSideArgs {
148
148
  positionTop: number;
149
149
  positionBottom: number;
150
150
  contentLayout: LayoutRectangle;
151
- dimensions: DisplayMetrics;
151
+ dimensions: ScaledSize;
152
152
  }
153
153
 
154
154
  function getSide({
@@ -272,7 +272,7 @@ function getLeftPosition(
272
272
  contentWidth: number,
273
273
  alignOffset: number,
274
274
  insets: SafeAreaInsets,
275
- dimensions: DisplayMetrics,
275
+ dimensions: ScaledSize,
276
276
  ) {
277
277
  let left = 0;
278
278
  if (align === "start") {
@@ -53,6 +53,7 @@ import type { EmptyStyles } from "../components/empty/types";
53
53
  import type { FieldStyles } from "../components/field/types";
54
54
  import type { IconButtonStyles } from "../components/icon-button/types";
55
55
  import type { InputStyles } from "../components/input/types";
56
+ import type { LinkStyles } from "../components/link";
56
57
  import type { MenuStyles } from "../components/menu/types";
57
58
  import type { PhoneInputStyles } from "../components/phone-input/types";
58
59
  import type { PopoverStyles } from "../components/popover/types";
@@ -115,6 +116,9 @@ export interface ComponentsConfig {
115
116
  input?: {
116
117
  styles?: InputStyles;
117
118
  };
119
+ link?: {
120
+ styles?: LinkStyles;
121
+ };
118
122
  menu?: {
119
123
  selectionIcon?: React.ComponentType<SvgProps>;
120
124
  styles?: MenuStyles;
@@ -1,15 +1,8 @@
1
- import type { HostInstance } from "react-native";
1
+ import type { TextInput, View } from "react-native";
2
2
  import type { SvgProps } from "./props.types";
3
3
 
4
- export type ViewRef = HostInstance;
5
- export type TextInputRef = HostInstance & {
6
- focus: () => void;
7
- blur: () => void;
8
- clear: () => void;
9
- isFocused: () => boolean;
10
- getNativeRef: () => HostInstance;
11
- setSelection: (start: number, end?: number) => void;
12
- };
4
+ export type ViewRef = React.ComponentRef<typeof View>;
5
+ export type TextInputRef = React.ComponentRef<typeof TextInput>;
13
6
 
14
7
  export type TextChild = string | number | bigint | boolean | null | undefined;
15
8
  export type TextChildren = TextChild | TextChild[];
@@ -2,7 +2,7 @@ import type React from "react";
2
2
  import type { ColorValue, StyleProp, TextStyle, ViewStyle } from "react-native";
3
3
 
4
4
  export type PropsWithRender<P> = P & {
5
- render?: (props: P) => React.ReactNode;
5
+ render?: React.ComponentType<P>;
6
6
  };
7
7
 
8
8
  export type PropsWithRequiredRender<P> = P & {
@@ -1,5 +1,6 @@
1
- import type { HostInstance, LayoutRectangle } from "react-native";
1
+ import type { LayoutRectangle } from "react-native";
2
2
  import type { LayoutPosition } from "../hooks";
3
+ import type { TextInputRef, ViewRef } from "../types/element.types";
3
4
 
4
5
  export const normalizeLayout = (layout: LayoutRectangle) => {
5
6
  const _layout = { ...layout };
@@ -22,7 +23,7 @@ const isValidNumber = (value: unknown): value is number => {
22
23
  };
23
24
 
24
25
  export const measureLayoutPosition = (
25
- ref: HostInstance | null,
26
+ ref: ViewRef | TextInputRef | null,
26
27
  callback: (layout: LayoutPosition) => void,
27
28
  ) => {
28
29
  if (ref && "getBoundingClientRect" in ref) {