@particle-network/ui-native 0.0.11 → 0.0.13

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 (75) hide show
  1. package/dist/components/Text/index.d.ts +1 -1
  2. package/dist/components/Text/index.js +0 -1
  3. package/dist/components/Text/text.js +12 -39
  4. package/dist/components/Text/text.style.d.ts +24 -0
  5. package/dist/components/Text/text.style.js +124 -0
  6. package/dist/components/Text/text.types.d.ts +0 -10
  7. package/dist/components/Text/text.types.js +0 -77
  8. package/dist/components/UXButton/button.js +3 -2
  9. package/dist/components/UXButton/button.styles.d.ts +2 -21
  10. package/dist/components/UXButton/button.styles.js +71 -45
  11. package/dist/components/UXButton/button.types.d.ts +15 -6
  12. package/dist/components/UXCheckbox/checkbox.js +2 -1
  13. package/dist/components/UXChip/chip.js +3 -1
  14. package/dist/components/UXChip/styles.d.ts +0 -10
  15. package/dist/components/UXChip/styles.js +13 -13
  16. package/dist/components/UXHint/index.js +2 -1
  17. package/dist/components/UXListBox/UXListBox.d.ts +12 -0
  18. package/dist/components/UXListBox/UXListBox.js +61 -0
  19. package/dist/components/UXListBox/UXListBoxItem.d.ts +3 -0
  20. package/dist/components/UXListBox/UXListBoxItem.js +57 -0
  21. package/dist/components/UXListBox/UXListBoxSection.d.ts +3 -0
  22. package/dist/components/UXListBox/UXListBoxSection.js +15 -0
  23. package/dist/components/UXListBox/index.d.ts +4 -0
  24. package/dist/components/UXListBox/index.js +4 -0
  25. package/dist/components/UXListBox/types.d.ts +25 -0
  26. package/dist/components/UXListBox/types.js +0 -0
  27. package/dist/components/UXModal/index.js +7 -5
  28. package/dist/components/UXRadio/radio.js +2 -1
  29. package/dist/components/UXSwitch/styles.js +2 -1
  30. package/dist/components/UXSwitch/switch.js +2 -2
  31. package/dist/components/UXTabs/styles.d.ts +4 -1
  32. package/dist/components/UXTabs/styles.js +38 -34
  33. package/dist/components/UXTabs/tab.js +33 -21
  34. package/dist/components/UXTabs/types.d.ts +16 -1
  35. package/dist/components/index.d.ts +1 -0
  36. package/dist/components/index.js +1 -0
  37. package/dist/components/input/styles.d.ts +1 -1
  38. package/dist/components/input/styles.js +19 -19
  39. package/dist/components/layout/Box/useBox.style.js +6 -6
  40. package/dist/config/config.default.d.ts +2 -0
  41. package/dist/config/config.default.js +55 -0
  42. package/dist/config/config.ux.d.ts +2 -0
  43. package/dist/config/config.ux.js +61 -0
  44. package/dist/config/index.d.ts +4 -0
  45. package/dist/config/index.js +7 -0
  46. package/dist/hooks/index.d.ts +2 -0
  47. package/dist/hooks/index.js +2 -0
  48. package/dist/hooks/useComponentConfig.d.ts +1 -0
  49. package/dist/hooks/useComponentConfig.js +7 -0
  50. package/dist/hooks/useMs.d.ts +3 -0
  51. package/dist/hooks/useMs.js +10 -0
  52. package/dist/icons/CheckIcon.d.ts +4 -0
  53. package/dist/icons/CheckIcon.js +20 -0
  54. package/dist/index.d.ts +2 -0
  55. package/dist/index.js +2 -0
  56. package/dist/provider/ThemeContext.d.ts +1 -1
  57. package/dist/provider/ThemeContext.js +5 -2
  58. package/dist/provider/ThemeProvider.d.ts +4 -2
  59. package/dist/provider/ThemeProvider.js +18 -6
  60. package/dist/theme/colors.d.ts +1 -1
  61. package/dist/theme/colors.js +2 -2
  62. package/dist/theme/index.d.ts +1 -3
  63. package/dist/theme/index.js +1 -12
  64. package/dist/theme/radius.d.ts +1 -1
  65. package/dist/theme/radius.js +3 -3
  66. package/dist/theme/spacing.d.ts +1 -1
  67. package/dist/theme/spacing.js +2 -2
  68. package/dist/theme/theme.d.ts +3 -0
  69. package/dist/theme/theme.js +13 -0
  70. package/dist/types/theme.d.ts +33 -1
  71. package/dist/utils/index.d.ts +2 -0
  72. package/dist/utils/index.js +2 -0
  73. package/dist/utils/mergeConfig.d.ts +8 -0
  74. package/dist/utils/mergeConfig.js +6 -0
  75. package/package.json +7 -5
@@ -1,20 +1,20 @@
1
1
  import { useMemo } from "react";
2
2
  import { StyleSheet } from "react-native";
3
- import { ms } from "react-native-size-matters";
4
- import { useColors } from "../../hooks/index.js";
3
+ import { useColors, useMs } from "../../hooks/index.js";
5
4
  import { disabledOpacity } from "../../theme/index.js";
6
- const sizeMap = {
7
- sm: ms(14),
8
- md: ms(16),
9
- lg: ms(18)
10
- };
11
- const fontSizeMap = {
12
- sm: ms(11),
13
- md: ms(12),
14
- lg: ms(14)
15
- };
16
5
  const useStyles = ({ size = 'md', color = 'default', variant = 'flat', isDisabled })=>{
17
6
  const { getColor } = useColors();
7
+ const { ms } = useMs();
8
+ const sizeMap = {
9
+ sm: ms(14),
10
+ md: ms(16),
11
+ lg: ms(18)
12
+ };
13
+ const fontSizeMap = {
14
+ sm: ms(11),
15
+ md: ms(12),
16
+ lg: ms(14)
17
+ };
18
18
  const height = useMemo(()=>sizeMap[size], [
19
19
  size
20
20
  ]);
@@ -67,4 +67,4 @@ const useStyles = ({ size = 'md', color = 'default', variant = 'flat', isDisable
67
67
  });
68
68
  return styles;
69
69
  };
70
- export { fontSizeMap, sizeMap, useStyles };
70
+ export { useStyles };
@@ -1,10 +1,11 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import "react";
3
- import { ms } from "react-native-size-matters";
3
+ import { useMs } from "../../hooks/index.js";
4
4
  import QuestionIcon from "../../icons/QuestionIcon.js";
5
5
  import { UXTooltip } from "../UXTooltip/index.js";
6
6
  const UXHint = (props)=>{
7
7
  const { content, children, iconStyle, ...restProps } = props;
8
+ const { ms } = useMs();
8
9
  return /*#__PURE__*/ jsx(UXTooltip, {
9
10
  content: content || children,
10
11
  ...restProps,
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { type Item, type UXListBoxProps } from './types';
3
+ interface ListBoxContextValue {
4
+ selectedValues: Set<string>;
5
+ selectionMode?: 'single' | 'multiple';
6
+ disabledKeys?: Set<string>;
7
+ onItemPress: (key: string) => void;
8
+ onAction?: (key: string) => void;
9
+ }
10
+ export declare const ListBoxContext: React.Context<ListBoxContextValue>;
11
+ export declare function UXListBox<T = Item>({ items, selectionMode, selectedValues: controlledselectedValues, disabledKeys, defaultselectedValues, onSelectionChange, onAction, disallowEmptySelection, 'aria-label': ariaLabel, children, }: UXListBoxProps<T>): React.JSX.Element;
12
+ export {};
@@ -0,0 +1,61 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import react, { useState } from "react";
3
+ import { ScrollView } from "react-native";
4
+ const ListBoxContext = /*#__PURE__*/ react.createContext({
5
+ selectedValues: new Set(),
6
+ onItemPress: ()=>null
7
+ });
8
+ function UXListBox({ items, selectionMode, selectedValues: controlledselectedValues, disabledKeys, defaultselectedValues, onSelectionChange, onAction, disallowEmptySelection = false, 'aria-label': ariaLabel, children }) {
9
+ const [internalselectedValues, setInternalselectedValues] = useState(()=>{
10
+ if ('all' === defaultselectedValues) return new Set();
11
+ return defaultselectedValues || new Set();
12
+ });
13
+ const selectedValues = void 0 !== controlledselectedValues ? controlledselectedValues : internalselectedValues;
14
+ const isControlled = void 0 !== controlledselectedValues;
15
+ const handleItemPress = (key)=>{
16
+ if (onAction && !selectionMode) return void onAction(key);
17
+ if (selectionMode) {
18
+ const newselectedValues = new Set('all' === selectedValues ? [] : selectedValues);
19
+ if ('single' === selectionMode) if (newselectedValues.has(key)) {
20
+ if (!disallowEmptySelection) newselectedValues.clear();
21
+ } else {
22
+ newselectedValues.clear();
23
+ newselectedValues.add(key);
24
+ }
25
+ else if ('multiple' === selectionMode) if (newselectedValues.has(key)) {
26
+ if (!disallowEmptySelection || newselectedValues.size > 1) newselectedValues.delete(key);
27
+ } else newselectedValues.add(key);
28
+ if (!isControlled) setInternalselectedValues(newselectedValues);
29
+ onSelectionChange?.(newselectedValues);
30
+ }
31
+ };
32
+ const renderChildren = ()=>{
33
+ if (items && 'function' == typeof children) {
34
+ const itemsArray = Array.from(items);
35
+ return itemsArray.map((item)=>{
36
+ const child = children(item);
37
+ return /*#__PURE__*/ react.cloneElement(child, {
38
+ key: child.key || item.key || item.value
39
+ });
40
+ });
41
+ }
42
+ return children;
43
+ };
44
+ const contextValue = {
45
+ selectedValues: 'all' === selectedValues ? new Set() : selectedValues,
46
+ selectionMode,
47
+ disabledKeys,
48
+ onItemPress: handleItemPress,
49
+ onAction
50
+ };
51
+ return /*#__PURE__*/ jsx(ListBoxContext.Provider, {
52
+ value: contextValue,
53
+ children: /*#__PURE__*/ jsx(ScrollView, {
54
+ showsVerticalScrollIndicator: false,
55
+ accessibilityRole: 'list',
56
+ accessibilityLabel: ariaLabel,
57
+ children: renderChildren()
58
+ })
59
+ });
60
+ }
61
+ export { ListBoxContext, UXListBox };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { type UXListBoxItemProps } from './types';
3
+ export declare const UXListBoxItem: React.FC<UXListBoxItemProps>;
@@ -0,0 +1,57 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useContext } from "react";
3
+ import { useMs } from "../../hooks/index.js";
4
+ import CheckIcon from "../../icons/CheckIcon.js";
5
+ import { HStack } from "../layout/HStack.js";
6
+ import { Text } from "../Text/index.js";
7
+ import { UXTouchableOpacity } from "../UXTouchableOpacity/index.js";
8
+ import { ListBoxContext } from "./UXListBox.js";
9
+ const disabledOpacity = 0.4;
10
+ const UXListBoxItem = ({ value = '', startContent, isDisabled = false, onPress, children })=>{
11
+ const { ms } = useMs();
12
+ const context = useContext(ListBoxContext);
13
+ const { selectedValues, selectionMode, disabledKeys, onItemPress } = context;
14
+ const isSelected = selectedValues.has(value);
15
+ const isItemDisabled = isDisabled || disabledKeys?.has(value);
16
+ const handlePress = ()=>{
17
+ if (isItemDisabled) return;
18
+ if (onPress) onPress();
19
+ else onItemPress(value);
20
+ };
21
+ return /*#__PURE__*/ jsxs(UXTouchableOpacity, {
22
+ radius: "sm",
23
+ ph: "md",
24
+ pv: "sm",
25
+ gap: 4,
26
+ items: "center",
27
+ justify: "between",
28
+ minH: 40,
29
+ disabled: isItemDisabled,
30
+ activeOpacity: 0.7,
31
+ accessibilityRole: "button",
32
+ accessibilityState: {
33
+ selected: isSelected,
34
+ disabled: isItemDisabled
35
+ },
36
+ onPress: handlePress,
37
+ children: [
38
+ /*#__PURE__*/ jsxs(HStack, {
39
+ gap: 4,
40
+ children: [
41
+ startContent,
42
+ /*#__PURE__*/ jsx(Text, {
43
+ body1Bold: true,
44
+ opacity: isItemDisabled ? disabledOpacity : 1,
45
+ color: isSelected ? 'foreground' : 'secondary',
46
+ children: children
47
+ })
48
+ ]
49
+ }),
50
+ selectionMode && isSelected ? /*#__PURE__*/ jsx(CheckIcon, {
51
+ size: ms(16),
52
+ color: "foreground"
53
+ }) : null
54
+ ]
55
+ });
56
+ };
57
+ export { UXListBoxItem };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { UXListBoxSectionProps } from './types';
3
+ export declare const UXListBoxSection: React.FC<UXListBoxSectionProps>;
@@ -0,0 +1,15 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import "react";
3
+ import { VStack } from "../layout/VStack.js";
4
+ import { Text } from "../Text/index.js";
5
+ const UXListBoxSection = ({ title, children })=>/*#__PURE__*/ jsxs(VStack, {
6
+ children: [
7
+ /*#__PURE__*/ jsx(Text, {
8
+ body1Bold: true,
9
+ mt: "md",
10
+ children: title
11
+ }),
12
+ children
13
+ ]
14
+ });
15
+ export { UXListBoxSection };
@@ -0,0 +1,4 @@
1
+ export type { UXListBoxItemProps, UXListBoxProps, UXListBoxSectionProps } from './types';
2
+ export { UXListBox } from './UXListBox';
3
+ export { UXListBoxItem } from './UXListBoxItem';
4
+ export { UXListBoxSection } from './UXListBoxSection';
@@ -0,0 +1,4 @@
1
+ import { UXListBox } from "./UXListBox.js";
2
+ import { UXListBoxItem } from "./UXListBoxItem.js";
3
+ import { UXListBoxSection } from "./UXListBoxSection.js";
4
+ export { UXListBox, UXListBoxItem, UXListBoxSection };
@@ -0,0 +1,25 @@
1
+ import { type ReactNode } from 'react';
2
+ export type Item = Record<string, unknown>;
3
+ export interface UXListBoxProps<T = Item> {
4
+ items?: Iterable<T>;
5
+ selectionMode?: 'single' | 'multiple';
6
+ selectedValues?: Set<string> | 'all';
7
+ disabledKeys?: Set<string>;
8
+ defaultselectedValues?: Set<string> | 'all';
9
+ onSelectionChange?: (keys: Set<string>) => void;
10
+ onAction?: (key: string) => void;
11
+ disallowEmptySelection?: boolean;
12
+ 'aria-label'?: string;
13
+ children?: ReactNode | ((item: T) => ReactNode);
14
+ }
15
+ export interface UXListBoxSectionProps {
16
+ title: string;
17
+ children?: ReactNode;
18
+ }
19
+ export interface UXListBoxItemProps {
20
+ value?: string;
21
+ startContent?: ReactNode;
22
+ isDisabled?: boolean;
23
+ onPress?: () => void;
24
+ children?: ReactNode;
25
+ }
File without changes
@@ -3,18 +3,20 @@ import react, { forwardRef, useCallback, useEffect, useMemo, useRef, useState }
3
3
  import { Animated, Dimensions, PanResponder, Platform, ScrollView, StyleSheet } from "react-native";
4
4
  import { Modal, Portal } from "react-native-paper";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
- import { ms } from "react-native-size-matters";
7
- import { useColors, useKeyboard } from "../../hooks/index.js";
6
+ import { useColors, useComponentConfig, useKeyboard, useMs } from "../../hooks/index.js";
8
7
  import { Box } from "../layout/Box/index.js";
9
8
  import { Circle } from "../layout/Circle.js";
10
9
  import { Flex } from "../layout/Flex/index.js";
11
10
  import { HStack } from "../layout/HStack.js";
12
11
  import { VStack } from "../layout/VStack.js";
13
12
  import { Text } from "../Text/index.js";
13
+ import { setColorWithOpacity } from "@particle-network/ui-shared";
14
14
  const { height } = Dimensions.get('window');
15
15
  const UXModal = /*#__PURE__*/ forwardRef((props, scrollViewRef)=>{
16
16
  const { style, contentStyle, isOpen, title, titleAlign = 'left', onClose, onVisibleChange, children, disableCloseBySwipe, closeByLineOnly, wrapPortal, footer, modalName, tip, keyboardAvoidPosition = 'container' } = props;
17
+ const { modal: modalConfig } = useComponentConfig();
17
18
  const { getColor } = useColors();
19
+ const { ms } = useMs();
18
20
  const insets = useSafeAreaInsets();
19
21
  const { keyboardHeight } = useKeyboard();
20
22
  const translateY = useRef(new Animated.Value(height)).current;
@@ -147,8 +149,8 @@ const UXModal = /*#__PURE__*/ forwardRef((props, scrollViewRef)=>{
147
149
  },
148
150
  container: {
149
151
  paddingHorizontal: ms(14),
150
- borderTopLeftRadius: 24,
151
- borderTopRightRadius: 24,
152
+ borderTopLeftRadius: modalConfig.radius,
153
+ borderTopRightRadius: modalConfig.radius,
152
154
  flex: 1,
153
155
  gap: ms(20),
154
156
  backgroundColor: getColor('overlay'),
@@ -183,7 +185,7 @@ const UXModal = /*#__PURE__*/ forwardRef((props, scrollViewRef)=>{
183
185
  ],
184
186
  theme: {
185
187
  colors: {
186
- backdrop: 'rgba(0, 0, 0, 0.8)'
188
+ backdrop: setColorWithOpacity(getColor('bg-200') ?? '#000000', 0.7)
187
189
  }
188
190
  },
189
191
  visible: isOpen,
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import { Pressable } from "react-native";
4
- import { ms } from "react-native-size-matters";
4
+ import { useMs } from "../../hooks/index.js";
5
5
  import RadioOffIcon from "../../icons/RadioOffIcon.js";
6
6
  import RadioOnIcon from "../../icons/RadioOnIcon.js";
7
7
  import { disabledOpacity } from "../../theme/index.js";
@@ -9,6 +9,7 @@ import { Flex } from "../layout/Flex/index.js";
9
9
  import { Text } from "../Text/index.js";
10
10
  import { useRadioGroup } from "./context.js";
11
11
  const UXRadio = ({ size, color, children, value, isDisabled, ...props })=>{
12
+ const { ms } = useMs();
12
13
  const groupContext = useRadioGroup();
13
14
  const { selectedValue, size: groupSize, color: groupColor, onValueChange, isDisabled: groupIsDisabled } = groupContext;
14
15
  const isSelected = selectedValue === value;
@@ -1,7 +1,8 @@
1
1
  import { useEffect, useMemo, useRef } from "react";
2
2
  import { Animated, StyleSheet } from "react-native";
3
- import { ms } from "react-native-size-matters";
3
+ import { useMs } from "../../hooks/index.js";
4
4
  const useStyles = ({ size = 'md', isSelected = false })=>{
5
+ const { ms } = useMs();
5
6
  const animatedValue = useRef(new Animated.Value(isSelected ? 1 : 0)).current;
6
7
  useEffect(()=>{
7
8
  Animated.timing(animatedValue, {
@@ -1,15 +1,15 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { Animated } from "react-native";
4
- import { ms } from "react-native-size-matters";
5
4
  import useUpdateEffect from "ahooks/es/useUpdateEffect";
6
- import { useColors } from "../../hooks/index.js";
5
+ import { useColors, useMs } from "../../hooks/index.js";
7
6
  import { disabledOpacity } from "../../theme/index.js";
8
7
  import { Text } from "../Text/index.js";
9
8
  import { UXTouchableOpacity } from "../UXTouchableOpacity/index.js";
10
9
  import { useStyles } from "./styles.js";
11
10
  const UXSwitch = (props)=>{
12
11
  const { color = 'primary', size = 'md', defaultSelected = false, isSelected: isSelectedProps = false, onValueChange, isReadOnly, isDisabled, children, ...flexProps } = props;
12
+ const { ms } = useMs();
13
13
  const [isSelected, setIsSelected] = useState(isSelectedProps || defaultSelected);
14
14
  useUpdateEffect(()=>{
15
15
  setIsSelected(isSelectedProps);
@@ -8,7 +8,7 @@ export declare const useStyles: (props: Partial<UXTabsProps> & {
8
8
  flex: number;
9
9
  justifyContent: "flex-start" | "space-between";
10
10
  borderRadius: number | undefined;
11
- height: number;
11
+ height: number | undefined;
12
12
  padding: number;
13
13
  opacity: number;
14
14
  };
@@ -27,4 +27,7 @@ export declare const useStyles: (props: Partial<UXTabsProps> & {
27
27
  fontWeight: "500";
28
28
  color: string | undefined;
29
29
  };
30
+ underline: {
31
+ backgroundColor: string | undefined;
32
+ };
30
33
  };
@@ -1,21 +1,15 @@
1
1
  import { useMemo } from "react";
2
2
  import { StyleSheet } from "react-native";
3
- import { ms } from "react-native-size-matters";
4
- import { useColors, useRadius } from "../../hooks/index.js";
3
+ import { useColors, useComponentConfig, useMs, useRadius } from "../../hooks/index.js";
5
4
  import { disabledOpacity } from "../../theme/index.js";
6
5
  const useStyles = (props)=>{
7
- const { size = 'md', radius, fullWidth, variant = 'solid', color = 'default', isDisabled, isSelected, w, gap } = props;
6
+ const { tabs: tabsConfig } = useComponentConfig();
7
+ const { size = 'md', radius = tabsConfig.defaultProps?.radius, fullWidth, variant = 'solid', color = 'default', isDisabled, isSelected, w, gap } = props;
8
8
  const { getColor } = useColors();
9
9
  const { getRadius } = useRadius();
10
+ const { ms } = useMs();
10
11
  const height = useMemo(()=>{
11
- if ('text' === variant) switch(size){
12
- case 'sm':
13
- return ms(16);
14
- case 'lg':
15
- return ms(20);
16
- default:
17
- return ms(18);
18
- }
12
+ if ('text' === variant || 'underlined' === variant) return;
19
13
  if ('solid' === variant) switch(size){
20
14
  case 'sm':
21
15
  return ms(24);
@@ -34,22 +28,16 @@ const useStyles = (props)=>{
34
28
  }
35
29
  }, [
36
30
  size,
37
- variant
31
+ variant,
32
+ ms
38
33
  ]);
39
- const fontSize = useMemo(()=>{
40
- switch(size){
41
- case 'sm':
42
- return ms(12);
43
- case 'lg':
44
- return ms(16);
45
- default:
46
- return ms(14);
47
- }
48
- }, [
49
- size
34
+ const fontSize = useMemo(()=>ms(tabsConfig.fontSize[size]), [
35
+ size,
36
+ ms,
37
+ tabsConfig.fontSize
50
38
  ]);
51
39
  const paddingHorizontal = useMemo(()=>{
52
- if ('text' === variant) return 0;
40
+ if ('text' === variant || 'underlined' === variant) return 0;
53
41
  switch(size){
54
42
  case 'sm':
55
43
  return ms(8);
@@ -60,11 +48,12 @@ const useStyles = (props)=>{
60
48
  }
61
49
  }, [
62
50
  size,
63
- variant
51
+ variant,
52
+ ms
64
53
  ]);
65
54
  const gapValue = useMemo(()=>{
66
55
  if (gap) return gap;
67
- if ('text' === variant) switch(size){
56
+ if ('text' === variant || 'underlined' === variant) switch(size){
68
57
  case 'sm':
69
58
  return ms(14);
70
59
  case 'lg':
@@ -77,7 +66,8 @@ const useStyles = (props)=>{
77
66
  }, [
78
67
  variant,
79
68
  size,
80
- gap
69
+ gap,
70
+ ms
81
71
  ]);
82
72
  const wrapperBackgroundColor = useMemo(()=>{
83
73
  if ('switch' === variant) return getColor('bg-200');
@@ -97,7 +87,8 @@ const useStyles = (props)=>{
97
87
  }, [
98
88
  variant,
99
89
  size,
100
- radius
90
+ radius,
91
+ ms
101
92
  ]);
102
93
  const wrapperPadding = useMemo(()=>{
103
94
  if ('solid' === variant) {
@@ -107,18 +98,22 @@ const useStyles = (props)=>{
107
98
  return 0;
108
99
  }, [
109
100
  variant,
110
- size
101
+ size,
102
+ ms
111
103
  ]);
112
104
  const tabBorderRadius = useMemo(()=>{
113
105
  if (radius) return getRadius(radius);
106
+ if ('text' === variant || 'underlined' === variant) return 0;
114
107
  return ms(6);
115
108
  }, [
116
109
  variant,
117
- radius
110
+ radius,
111
+ ms,
112
+ getRadius
118
113
  ]);
119
114
  const tabBg = useMemo(()=>{
120
115
  if (!isSelected) return 'transparent';
121
- if ('text' === variant) return 'transparent';
116
+ if ('text' === variant || 'underlined' === variant) return 'transparent';
122
117
  if ('default' === color) {
123
118
  if ('switch' === variant) return getColor('tertiary');
124
119
  return getColor('bg-200');
@@ -132,7 +127,7 @@ const useStyles = (props)=>{
132
127
  ]);
133
128
  const tabTextColor = useMemo(()=>{
134
129
  if (!isSelected) return getColor('secondary');
135
- if ('text' === variant) {
130
+ if ('text' === variant || 'underlined' === variant) {
136
131
  if ('default' === color) return getColor('foreground');
137
132
  return getColor(color);
138
133
  }
@@ -156,7 +151,11 @@ const useStyles = (props)=>{
156
151
  opacity: isDisabled ? disabledOpacity : 1
157
152
  },
158
153
  tab: {
159
- flexGrow: 'text' === variant || 'light' === variant ? 0 : 1,
154
+ flexGrow: [
155
+ 'text',
156
+ 'light',
157
+ 'underlined'
158
+ ].includes(variant) ? 0 : 1,
160
159
  height: '100%',
161
160
  alignItems: 'center',
162
161
  justifyContent: 'center',
@@ -169,6 +168,9 @@ const useStyles = (props)=>{
169
168
  lineHeight: fontSize + ms(4),
170
169
  fontWeight: '500',
171
170
  color: tabTextColor
171
+ },
172
+ underline: {
173
+ backgroundColor: isSelected ? tabTextColor : 'transparent'
172
174
  }
173
175
  }), [
174
176
  variant,
@@ -184,7 +186,9 @@ const useStyles = (props)=>{
184
186
  isDisabled,
185
187
  tabTextColor,
186
188
  fullWidth,
187
- w
189
+ w,
190
+ ms,
191
+ isSelected
188
192
  ]);
189
193
  return styles;
190
194
  };
@@ -1,6 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useCallback } from "react";
3
3
  import DotIcon from "../../icons/DotIcon.js";
4
+ import { Box } from "../layout/Box/index.js";
4
5
  import { HStack } from "../layout/HStack.js";
5
6
  import { Text } from "../Text/index.js";
6
7
  import { UXTouchableOpacity } from "../UXTouchableOpacity/index.js";
@@ -23,34 +24,45 @@ const UXTab = ({ tabKey = '', title, icon, style, notification })=>{
23
24
  radius,
24
25
  isSelected
25
26
  });
26
- return /*#__PURE__*/ jsx(UXTouchableOpacity, {
27
+ return /*#__PURE__*/ jsxs(UXTouchableOpacity, {
27
28
  activeOpacity: 0.7,
28
29
  disabled: isDisabled,
30
+ gap: 8,
31
+ direction: "column",
32
+ items: "center",
29
33
  style: [
30
34
  styles.tab,
31
35
  style
32
36
  ],
33
37
  onPress: handlePress,
34
- children: /*#__PURE__*/ jsxs(HStack, {
35
- gap: 4,
36
- position: "relative",
37
- children: [
38
- 'function' == typeof icon ? icon(isSelected) : icon,
39
- 'function' == typeof title ? title(isSelected) : /*#__PURE__*/ jsx(Text, {
40
- style: styles.tabText,
41
- children: title
42
- }),
43
- notification ? /*#__PURE__*/ jsx(DotIcon, {
44
- color: "danger",
45
- size: 5,
46
- style: {
47
- position: 'absolute',
48
- right: -4,
49
- top: 0
50
- }
51
- }) : null
52
- ]
53
- })
38
+ children: [
39
+ /*#__PURE__*/ jsxs(HStack, {
40
+ gap: 4,
41
+ position: "relative",
42
+ children: [
43
+ 'function' == typeof icon ? icon(isSelected) : icon,
44
+ 'function' == typeof title ? title(isSelected) : /*#__PURE__*/ jsx(Text, {
45
+ style: styles.tabText,
46
+ children: title
47
+ }),
48
+ notification ? /*#__PURE__*/ jsx(DotIcon, {
49
+ color: "danger",
50
+ size: 5,
51
+ style: {
52
+ position: 'absolute',
53
+ right: -4,
54
+ top: 0
55
+ }
56
+ }) : null
57
+ ]
58
+ }),
59
+ 'underlined' === variant && /*#__PURE__*/ jsx(Box, {
60
+ w: 24,
61
+ h: 2,
62
+ radius: 4,
63
+ style: styles.underline
64
+ })
65
+ ]
54
66
  });
55
67
  };
56
68
  UXTab.displayName = 'UXTab';
@@ -4,8 +4,23 @@ import type { UXForegroundColor, UXSize } from '@particle-network/ui-shared';
4
4
  import type { HStackProps } from '../layout/HStack';
5
5
  export interface UXTabsProps extends HStackProps {
6
6
  color?: UXForegroundColor;
7
+ /**
8
+ * 高度对比
9
+ * | variant | sm | md | lg |
10
+ * | ------- | --- | --- | --- |
11
+ * | solid | - | 30 | 40 |
12
+ * | switch | 24 | 30 | 34 |
13
+ * | light | 24 | 30 | 34 |
14
+ *
15
+ * variant-text 字号对比
16
+ * | text | ux-pro | ux |
17
+ * | ------- | ------ | ----- |
18
+ * | sm | 12 | 14 |
19
+ * | md | 14 | 16 |
20
+ * | lg | 16 | 18 |
21
+ */
7
22
  size?: UXSize;
8
- variant?: 'solid' | 'light' | 'text' | 'switch';
23
+ variant?: 'solid' | 'light' | 'text' | 'switch' | 'underlined';
9
24
  selectedKey?: string;
10
25
  defaultSelectedKey?: string;
11
26
  onSelectionChange?: (key: string) => void;
@@ -13,6 +13,7 @@ export * from './UXCheckbox';
13
13
  export * from './UXChip';
14
14
  export * from './UXDivider';
15
15
  export * from './UXHint';
16
+ export * from './UXListBox';
16
17
  export * from './UXModal';
17
18
  export * from './UXPressable';
18
19
  export * from './UXRadio';
@@ -13,6 +13,7 @@ export * from "./UXCheckbox/index.js";
13
13
  export * from "./UXChip/index.js";
14
14
  export * from "./UXDivider/index.js";
15
15
  export * from "./UXHint/index.js";
16
+ export * from "./UXListBox/index.js";
16
17
  export * from "./UXModal/index.js";
17
18
  export * from "./UXPressable/index.js";
18
19
  export * from "./UXRadio/index.js";
@@ -2,7 +2,7 @@ import type { UXInputCommonProps } from './types';
2
2
  type UseStylesProps = UXInputCommonProps & {
3
3
  isFocused?: boolean;
4
4
  };
5
- export declare const useStyles: ({ isInvalid, isDisabled, fullWidth, isFocused, color, size, variant, radius, width: widthProp, textAlign, }: UseStylesProps) => {
5
+ export declare const useStyles: (props: UseStylesProps) => {
6
6
  container: {
7
7
  width: number | import("react-native").Animated.AnimatedNode | "auto" | `${number}%`;
8
8
  height: number;