Преглед на файлове

Feature: Chip Component completed.

lfabl преди 1 седмица
родител
ревизия
ac78559498

+ 19 - 1
example/src/pages/home/index.tsx

@@ -31,7 +31,8 @@ import {
     Dialog,
     Switch,
     Text,
-    Sticker
+    Sticker,
+    Chip
 } from "ncore-ui-kit-mobile";
 import {
     useNavigation
@@ -368,7 +369,24 @@ const Home = () => {
             </Fragment>;
         }}
     >
+        <Chip
+            spreadBehaviour="free"
+            title="test"
+            isLoading={false}
+            isDisabled={false}
+            icon={({
+                customColor,
+                style,
+                color,
+                size
+            }) => <HomeIcon
+                color={customColor ? customColor : colors.content.icon[color]}
+                size={size}
+                style={style}
+            />}
+        />
         <Sticker
+            spreadBehaviour="free"
             title="test"
             icon={({
                 style,

+ 0 - 1
siradakiler.txt

@@ -1 +0,0 @@
--> Chip

+ 29 - 30
src/assets/svg/loadingIcon/index.tsx

@@ -58,39 +58,38 @@ const SvgLoadingIcon = ({
         ]
     });
 
-    return (
-        <View
+    return <View
+        style={{
+            height: size,
+            width: size,
+            ...props?.style
+        }}
+    >
+        <Animated.View
             style={{
-                height: size,
-                width: size
+                transform: [{
+                    rotate: rotate
+                }]
             }}
         >
-            <Animated.View
-                style={{
-                    transform: [{
-                        rotate: rotate
-                    }]
-                }}
+            <Svg
+                height={size}
+                width={size}
+                fill="none"
+                style={props.style}
+                {...props}
             >
-                <Svg
-                    height={size}
-                    width={size}
-                    fill="none"
-                    style={props.style}
-                    {...props}
-                >
-                    <Path
-                        d="M11.885 7.303 19 3.194l7.115 4.109v8.215l7.095 4.09v8.215l-7.115 4.108-7.076-4.108-7.114 4.108-7.115-4.108v-8.216l7.095-4.089V7.303Z"
-                        stroke={customColor ? customColor : colors.content.icon[color]}
-                        transform={`scale(${1 / pathScale})`}
-                        strokeLinejoin="round"
-                        strokeLinecap="round"
-                        clipRule="evenodd"
-                        strokeWidth={3}
-                    />
-                </Svg>
-            </Animated.View>
-        </View>
-    );
+                <Path
+                    d="M11.885 7.303 19 3.194l7.115 4.109v8.215l7.095 4.09v8.215l-7.115 4.108-7.076-4.108-7.114 4.108-7.115-4.108v-8.216l7.095-4.089V7.303Z"
+                    stroke={customColor ? customColor : colors.content.icon[color]}
+                    transform={`scale(${1 / pathScale})`}
+                    strokeLinejoin="round"
+                    strokeLinecap="round"
+                    clipRule="evenodd"
+                    strokeWidth={3}
+                />
+            </Svg>
+        </Animated.View>
+    </View>;
 };
 export default SvgLoadingIcon;

+ 183 - 0
src/components/chip/index.tsx

@@ -0,0 +1,183 @@
+import {
+    type FC
+} from "react";
+import {
+    TouchableOpacity,
+    View
+} from "react-native";
+import type IChipProps from "./type";
+import stylesheet, {
+    getChipType,
+    useStyles
+} from "./stylesheet";
+import {
+    NCoreUIKitTheme
+} from "../../core/hooks";
+import type {
+    INCoreUIKitIconProps
+} from "../../types";
+import type ITextProps from "../text/type";
+import {
+    X as XIcon
+} from "lucide-react-native";
+import Text from "../text";
+import Loading from "../loading";
+
+const Chip: FC<IChipProps> = ({
+    displayBehaviourWhileLoading = "disabled",
+    spreadBehaviour = "baseline",
+    isClosable = true,
+    type = "neutral",
+    customTitleColor,
+    customIconColor,
+    size = "medium",
+    icon: IconProp,
+    customColor,
+    customTheme,
+    titleStyle,
+    isDisabled,
+    isLoading,
+    onPress,
+    title,
+    style,
+    ...props
+}) => {
+    const {
+        typography,
+        radiuses,
+        spaces,
+        colors
+    } = NCoreUIKitTheme.useContext(customTheme);
+
+    const currentType = getChipType({
+        type
+    });
+
+    const {
+        titleContainer: titleContainerDynamicStyle,
+        container: containerDynamicStyle,
+        loading: loadingDynamicStyle,
+        overlay: overlayDynamicStyle,
+        close: closeDynamicStyle,
+        title: titleDynamicStyle,
+        icon: iconDynamicStyle
+    } = useStyles({
+        displayBehaviourWhileLoading,
+        spreadBehaviour,
+        customColor,
+        currentType,
+        isDisabled,
+        isClosable,
+        isLoading,
+        radiuses,
+        spaces,
+        colors,
+        size,
+        type
+    });
+
+    const iconProps: INCoreUIKitIconProps = {
+        color: customIconColor ? customIconColor : currentType.iconColor
+    };
+
+    const titleProps: ITextProps = {
+        color: customTitleColor ? customTitleColor : currentType.titleColor
+    };
+
+    if (isDisabled || (displayBehaviourWhileLoading === "disabled" && isLoading)) {
+        const stateType = type === "danger" ? "error" : type;
+
+        titleProps.customColor = colors.system.state.content.disabled[stateType];
+        iconProps.customColor = colors.system.state.content.disabled[stateType];
+    }
+
+    const contentSize = size === "large" ? "bodyLargeSize" : size === "medium" ? "bodyMediumSize" : "bodySmallSize";
+
+    const renderIcon = () => {
+        const iconSize = typography[contentSize].fontSize + 4;
+
+        if(isLoading) {
+            return <Loading
+                {...iconProps}
+                style={loadingDynamicStyle}
+                size={iconSize}
+            />;
+        }
+
+        if(!IconProp) {
+            return null;
+        }
+
+        return <IconProp
+            {...iconProps}
+            color={iconProps.color as keyof NCoreUIKit.IconContentColors}
+            style={iconDynamicStyle}
+            size={iconSize}
+        />;
+    };
+
+    const renderTitle = () => {
+        if (!title) {
+            return null;
+        }
+
+        return <View
+            style={[
+                stylesheet.titleContainer,
+                titleContainerDynamicStyle
+            ]}
+        >
+            <Text
+                style={[
+                    titleStyle,
+                    stylesheet.title,
+                    titleDynamicStyle
+                ]}
+                variant={contentSize}
+                {...titleProps}
+            >
+                {title}
+            </Text>
+        </View>;
+    };
+
+    const renderClose = () => {
+        if(!isClosable) {
+            return null;
+        }
+
+        return <XIcon
+            color={isDisabled || (displayBehaviourWhileLoading && isLoading) ? colors.content.icon.disabled : type === "neutral" ? colors.content.icon.low : colors.content.icon[type === "primary" ? "onPrimary" : type]}
+            size={typography[contentSize].fontSize + 4}
+            style={closeDynamicStyle}
+        />;
+    };
+
+    const renderOverlay = () => {
+        return <View
+            style={[
+                stylesheet.overlay,
+                overlayDynamicStyle
+            ]}
+        />;
+    };
+
+    return <TouchableOpacity
+        {...props}
+        disabled={isDisabled || isLoading}
+        style={[
+            style,
+            stylesheet.container,
+            containerDynamicStyle
+        ]}
+        onPress={isDisabled || isLoading ? undefined : () => {
+            if(onPress) onPress();
+        }}
+    >
+        {renderIcon()}
+        {renderTitle()}
+        {renderClose()}
+        {renderOverlay()}
+    </TouchableOpacity>;
+};
+export default Chip;

+ 172 - 0
src/components/chip/stylesheet.ts

@@ -0,0 +1,172 @@
+import {
+    type TextStyle,
+    type ViewStyle,
+    StyleSheet
+} from "react-native";
+import {
+    type ChipDynamicStyleType,
+    type ChipTypeConstantType,
+    type ChipTypes,
+    type ChipType
+} from "./type";
+import type {
+    Mutable
+} from "../../types";
+
+export const CHECK_BOX_TYPE_STYLES: Record<
+    ChipType,
+    {
+        containerColor: keyof NCoreUIKit.ContainerContentColors;
+        titleColor: keyof NCoreUIKit.TextContentColors;
+        iconColor: keyof NCoreUIKit.IconContentColors;
+    }
+> = {
+    primary: {
+        containerColor: "mid",
+        titleColor: "mid",
+        iconColor: "mid"
+    },
+    danger: {
+        containerColor: "danger",
+        titleColor: "danger",
+        iconColor: "danger"
+    },
+    success: {
+        containerColor: "success",
+        titleColor: "success",
+        iconColor: "success"
+    },
+    warning: {
+        containerColor: "warning",
+        titleColor: "warning",
+        iconColor: "warning"
+    },
+    info: {
+        containerColor: "info",
+        titleColor: "info",
+        iconColor: "info"
+    },
+    neutral: {
+        containerColor: "mid",
+        titleColor: "mid",
+        iconColor: "mid"
+    }
+};
+
+export const getChipType = ({
+    type
+}: ChipTypeConstantType): ChipTypes => {
+    const currentType = CHECK_BOX_TYPE_STYLES[type];
+
+    return currentType;
+};
+
+const stylesheet = StyleSheet.create({
+    container: {
+        backgroundColor: "transparent",
+        justifyContent: "center",
+        flexDirection: "row",
+        alignItems: "center",
+        position: "relative"
+    },
+    titleContainer: {
+        justifyContent: "flex-start",
+        flexDirection: "row",
+        alignItems: "center"
+    },
+    title: {
+        textAlign: "center",
+        zIndex: 99,
+        margin: 0
+    },
+    overlay: {
+        position: "absolute",
+        display: "none",
+        zIndex: 98,
+        bottom: 0,
+        right: 0,
+        left: 0,
+        top: 0
+    }
+});
+
+export const useStyles = ({
+    displayBehaviourWhileLoading,
+    spreadBehaviour,
+    customColor,
+    currentType,
+    isClosable,
+    isDisabled,
+    isLoading,
+    radiuses,
+    spaces,
+    colors,
+    size,
+    type
+}: ChipDynamicStyleType) => {
+    const styleType = type === "danger" ? "error" : type;
+
+    const styles = {
+        container: {
+            paddingHorizontal: size === "small" ? spaces.spacingSm : spaces.spacingMd,
+            paddingVertical: size === "small" ? spaces.spacingXs : spaces.spacingSm,
+            backgroundColor: colors.content.container[currentType.containerColor],
+            borderRadius: radiuses.chip
+        } as Mutable<ViewStyle>,
+        titleContainer: {
+        } as Mutable<ViewStyle>,
+        title: {
+        } as Mutable<TextStyle>,
+        icon: {
+            marginRight: spaces.spacingXs
+        } as Mutable<ViewStyle>,
+        close: {
+            marginLeft: spaces.spacingXs
+        } as Mutable<ViewStyle>,
+        loading: {
+        } as Mutable<ViewStyle>,
+        overlay: {
+        } as Mutable<ViewStyle>
+    };
+
+    if(customColor) {
+        styles.container.backgroundColor = colors.content.container[customColor];
+    }
+
+    if(isClosable) {
+        styles.container.paddingHorizontal = 0;
+
+        styles.container.paddingLeft = size === "small" ? spaces.spacingSm : spaces.spacingMd;
+        styles.container.paddingRight = spaces.spacingSm;
+    }
+
+    if (spreadBehaviour === "baseline") {
+        styles.container.alignSelf = spreadBehaviour;
+        styles.container.width = "auto";
+    }
+
+    if(isLoading) {
+        if(displayBehaviourWhileLoading === "disabled") {
+            styles.overlay.display = "flex";
+
+            if (displayBehaviourWhileLoading === "disabled") {
+                styles.container.borderColor = colors.system.state.overlay.disabled[styleType];
+
+                styles.overlay.backgroundColor = colors.system.state.overlay.disabled[styleType];
+                styles.overlay.display = "flex";
+            }
+        }
+
+        styles.titleContainer.marginLeft = spaces.spacingXs;
+    }
+
+    if (isDisabled) {
+        styles.container.borderColor = colors.system.state.overlay.disabled[styleType];
+
+        styles.overlay.backgroundColor = colors.system.state.overlay.disabled[styleType];
+        styles.overlay.display = "flex";
+    }
+
+    return styles;
+};
+export default stylesheet;

+ 68 - 0
src/components/chip/type.ts

@@ -0,0 +1,68 @@
+import {
+    type ViewStyle,
+    type StyleProp,
+    type TextStyle
+} from "react-native";
+import type {
+    NCoreUIKitIcon
+} from "../../types";
+
+export type ChipDynamicStyleType = {
+    displayBehaviourWhileLoading?: ChipDisplayBehaviourWhileLoading;
+    customColor?: keyof NCoreUIKit.ContainerContentColors;
+    radiuses: NCoreUIKit.ActivePalette["radiuses"];
+    spaces: NCoreUIKit.ActivePalette["spaces"];
+    colors: NCoreUIKit.ActivePalette["colors"];
+    spreadBehaviour?: ChipSpreadBehaviour;
+    currentType: ChipTypes;
+    isDisabled?: boolean;
+    isLoading?: boolean;
+    isClosable: boolean;
+    size?: ChipSizeType;
+    type: ChipType;
+};
+
+export type ChipTypes = {
+    containerColor: keyof NCoreUIKit.ContainerContentColors;
+    titleColor: keyof NCoreUIKit.TextContentColors;
+    iconColor: keyof NCoreUIKit.IconContentColors;
+};
+
+export type ChipTypeConstantType = {
+    type: ChipType;
+};
+
+export type ChipType = "primary" | "danger" | "warning" | "neutral" | "success" | "info";
+
+export type ChipDisplayBehaviourWhileLoading = "none" | "disabled";
+
+export type ChipSizeType = "small" | "medium" | "large";
+
+export type ChipSpreadBehaviour = "baseline" | "free";
+
+interface IChipProps {
+    displayBehaviourWhileLoading?: ChipDisplayBehaviourWhileLoading;
+    titleStyle?: StyleProp<TextStyle>[] | StyleProp<TextStyle>;
+    customTheme?: {
+        gapPropagation?: keyof NCoreUIKit.GapPropagationKey;
+        sharpness?: keyof NCoreUIKit.SharpnessKey;
+        paletteKey?: keyof NCoreUIKit.PaletteKey;
+        themeKey?: keyof NCoreUIKit.ThemeKey;
+    };
+    style?: StyleProp<ViewStyle>[] | StyleProp<ViewStyle>;
+    customTitleColor?: keyof NCoreUIKit.TextContentColors;
+    customColor?: keyof NCoreUIKit.ContainerContentColors;
+    customIconColor?: keyof NCoreUIKit.IconContentColors;
+    spreadBehaviour?: ChipSpreadBehaviour;
+    icon?: NCoreUIKitIcon;
+    isClosable?: boolean;
+    isDisabled?: boolean;
+    onPress?: () => void;
+    isLoading?: boolean;
+    size?: ChipSizeType;
+    type?: ChipType;
+    title?: string;
+}
+export type {
+    IChipProps as default
+};

+ 4 - 0
src/components/index.ts

@@ -134,6 +134,10 @@ export {
     default as Sticker
 } from "./sticker";
 
+export {
+    default as Chip
+} from "./chip";
+
 export type {
     EnterMarkdownTypes,
     CodeMarkdownTypes,

+ 2 - 0
src/components/sticker/index.tsx

@@ -19,6 +19,7 @@ import type ITextProps from "../text/type";
 import Text from "../text";
 
 const Sticker: FC<IStickerProps> = ({
+    spreadBehaviour = "baseline",
     iconPosition = "left",
     type = "neutral",
     customTitleColor,
@@ -49,6 +50,7 @@ const Sticker: FC<IStickerProps> = ({
         title: titleDynamicStyle,
         icon: iconDynamicStyle
     } = useStyles({
+        spreadBehaviour,
         iconPosition,
         customColor,
         currentType,

+ 6 - 0
src/components/sticker/stylesheet.ts

@@ -80,6 +80,7 @@ const stylesheet = StyleSheet.create({
 });
 
 export const useStyles = ({
+    spreadBehaviour,
     iconPosition,
     customColor,
     currentType,
@@ -107,6 +108,11 @@ export const useStyles = ({
         styles.container.backgroundColor = colors.content.container[customColor];
     }
 
+    if (spreadBehaviour === "baseline") {
+        styles.container.alignSelf = spreadBehaviour;
+        styles.container.width = "auto";
+    }
+
     if(iconPosition === "right") {
         styles.icon.marginLeft = spaces.spacingXs;
     } else {

+ 4 - 0
src/components/sticker/type.ts

@@ -12,6 +12,7 @@ export type StickerDynamicStyleType = {
     radiuses: NCoreUIKit.ActivePalette["radiuses"];
     spaces: NCoreUIKit.ActivePalette["spaces"];
     colors: NCoreUIKit.ActivePalette["colors"];
+    spreadBehaviour?: StickerSpreadBehaviour;
     iconPosition?: StickerIconPositionType;
     currentType: StickerTypes;
     size?: StickerSizeType;
@@ -31,6 +32,8 @@ export type StickerType = "primary" | "danger" | "warning" | "neutral" | "succes
 
 export type StickerSizeType = "small" | "medium" | "large";
 
+export type StickerSpreadBehaviour = "baseline" | "free";
+
 export type StickerIconPositionType = "left" | "right";
 
 interface IStickerProps {
@@ -45,6 +48,7 @@ interface IStickerProps {
     customTitleColor?: keyof NCoreUIKit.TextContentColors;
     customColor?: keyof NCoreUIKit.ContainerContentColors;
     customIconColor?: keyof NCoreUIKit.IconContentColors;
+    spreadBehaviour?: StickerSpreadBehaviour;
     iconPosition?: StickerIconPositionType;
     size?: StickerSizeType;
     icon?: NCoreUIKitIcon;

+ 1 - 0
src/index.tsx

@@ -40,6 +40,7 @@ export {
     Button,
     Modal,
     Toast,
+    Chip,
     Text
 } from "./components";