diff --git a/assets/icons/lock.svg b/assets/icons/lock.svg
new file mode 100644
index 0000000000..bfce8aadd3
--- /dev/null
+++ b/assets/icons/lock.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/components/inputs/SelectInput.tsx b/packages/components/inputs/SelectInput.tsx
new file mode 100644
index 0000000000..ae7d06b378
--- /dev/null
+++ b/packages/components/inputs/SelectInput.tsx
@@ -0,0 +1,232 @@
+import React, { ReactElement, useState } from "react";
+import {
+ View,
+ ScrollView,
+ StyleSheet,
+ StyleProp,
+ ViewStyle,
+} from "react-native";
+
+import { Label } from "./TextInputCustom";
+import chevronDownSVG from "../../../assets/icons/chevron-down.svg";
+import chevronUpSVG from "../../../assets/icons/chevron-up.svg";
+import lockSVG from "../../../assets/icons/lock.svg";
+import {
+ neutral00,
+ neutral33,
+ neutral77,
+ neutralA3,
+ secondaryColor,
+} from "../../utils/style/colors";
+import { fontMedium13, fontSemibold14 } from "../../utils/style/fonts";
+import { layout } from "../../utils/style/layout";
+import { BrandText } from "../BrandText";
+import { SVG } from "../SVG";
+import { CustomPressable } from "../buttons/CustomPressable";
+import { SpacerColumn, SpacerRow } from "../spacer";
+
+export type SelectInputDataValue = string | number;
+
+export type SelectInputData = {
+ label: string;
+ value: SelectInputDataValue;
+ iconComponent?: ReactElement;
+};
+
+type Props = {
+ data: SelectInputData[];
+ placeHolder?: string;
+ selectedData: SelectInputData;
+ setData: (data: SelectInputData) => void;
+ disabled?: boolean;
+ style?: StyleProp;
+ boxStyle?: StyleProp;
+ label?: string;
+ isRequired?: boolean;
+};
+
+export const SelectInput: React.FC = ({
+ data,
+ placeHolder,
+ selectedData,
+ setData,
+ disabled,
+ style,
+ boxStyle,
+ label,
+ isRequired,
+}) => {
+ const [openMenu, setOpenMenu] = useState(false);
+ const [hoveredIndex, setHoveredIndex] = useState(0);
+ const [hovered, setHovered] = useState(false);
+
+ const getScrollViewStyle = () => {
+ if (data.length > 5) {
+ return [styles.dropdownMenu, { height: 200 }];
+ }
+ return styles.dropdownMenu;
+ };
+
+ return (
+ setHovered(true)}
+ onHoverOut={() => setHovered(false)}
+ onPress={() => {
+ if (!disabled || data.length) setOpenMenu((value) => !value);
+ }}
+ disabled={disabled || !data.length}
+ >
+ {label && (
+ <>
+
+
+ >
+ )}
+
+
+
+ {selectedData.iconComponent && (
+ <>
+ {selectedData.iconComponent}
+
+ >
+ )}
+
+
+ {selectedData?.label ? selectedData.label : placeHolder}
+
+
+
+
+
+
+ {/*TODO: If the opened menu appears under other elements, you'll may need to set zIndex:-1 or something to these elements*/}
+ {openMenu && (
+
+ {data.map((item, index) => (
+ {
+ setHoveredIndex(index + 1);
+ setHovered(true);
+ }}
+ onHoverOut={() => {
+ setHoveredIndex(0);
+ setHovered(false);
+ }}
+ onPress={() => {
+ setData(item);
+ setOpenMenu(false);
+ }}
+ key={index}
+ style={styles.dropdownMenuRow}
+ >
+
+ {item.iconComponent && (
+ <>
+ {item.iconComponent}
+
+ >
+ )}
+
+
+ {item.label}
+
+
+
+ ))}
+
+ )}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ selectInputLabel: StyleSheet.flatten([fontSemibold14, { color: neutralA3 }]),
+ selectInput: {
+ backgroundColor: neutral00,
+ fontSize: 14,
+ fontWeight: 600,
+ color: secondaryColor,
+ borderColor: neutral33,
+ borderWidth: 1,
+ borderRadius: 12,
+ padding: layout.padding_x1_5,
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ },
+ inputContainer: {
+ backgroundColor: neutral00,
+ borderWidth: 1,
+ borderColor: neutral33,
+ borderRadius: 12,
+ paddingHorizontal: layout.padding_x1_5,
+ },
+ inputItemStyle: {
+ backgroundColor: "#292929",
+ color: neutralA3,
+ paddingVertical: layout.padding_x1_5,
+ paddingHorizontal: layout.padding_x1,
+ },
+ iconLabel: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+
+ dropdownMenu: {
+ backgroundColor: "#292929",
+ borderWidth: 1,
+ borderColor: neutral33,
+ borderRadius: 12,
+ padding: layout.padding_x1,
+ position: "absolute",
+ top: 52,
+ width: "100%",
+ zIndex: 10,
+ },
+ dropdownMenuText: StyleSheet.flatten([fontMedium13]),
+ dropdownMenuRow: {
+ borderRadius: 6,
+ padding: layout.padding_x1,
+ },
+ // dropdownMenuRow: {
+ // backgroundColor: neutral00,
+ // borderRadius: 6,
+ // padding: layout.padding_x1,
+ // },
+});
diff --git a/packages/components/inputs/TextInputCustom.tsx b/packages/components/inputs/TextInputCustom.tsx
index 84a9681655..9f91a19b8f 100644
--- a/packages/components/inputs/TextInputCustom.tsx
+++ b/packages/components/inputs/TextInputCustom.tsx
@@ -6,6 +6,7 @@ import React, {
useEffect,
useMemo,
useRef,
+ useState,
} from "react";
import {
RegisterOptions,
@@ -16,7 +17,7 @@ import {
FieldValues,
} from "react-hook-form";
import {
- Pressable,
+ ActivityIndicator,
StyleProp,
StyleSheet,
TextInput,
@@ -27,7 +28,6 @@ import {
} from "react-native";
import { SvgProps } from "react-native-svg";
-// import { TextInputLabelProps } from "./TextInputOutsideLabel";
import { DEFAULT_FORM_ERRORS } from "../../utils/errors";
import { handleKeyPress } from "../../utils/keyboard";
import {
@@ -39,22 +39,19 @@ import {
neutralA3,
secondaryColor,
} from "../../utils/style/colors";
-import {
- fontMedium10,
- fontSemibold14,
- fontSemibold20,
-} from "../../utils/style/fonts";
+import { fontMedium10, fontSemibold14 } from "../../utils/style/fonts";
import { layout } from "../../utils/style/layout";
import { BrandText } from "../BrandText";
import { ErrorText } from "../ErrorText";
import { SVG } from "../SVG";
import { TertiaryBox } from "../boxes/TertiaryBox";
+import { CustomPressable } from "../buttons/CustomPressable";
import { SpacerColumn, SpacerRow } from "../spacer";
export interface TextInputCustomProps
extends Omit {
label: string;
- variant?: "regular" | "labelOutside" | "noCropBorder" | "noStyle";
+ variant?: "regular" | "labelOutside" | "noStyle";
iconSVG?: React.FC;
placeHolder?: string;
squaresBackgroundColor?: string;
@@ -72,7 +69,9 @@ export interface TextInputCustomProps
defaultValue?: PathValue>;
subtitle?: React.ReactElement;
hideLabel?: boolean;
+ errorStyle?: ViewStyle;
valueModifier?: (value: string) => string;
+ isLoading?: boolean;
labelStyle?: TextStyle;
containerStyle?: ViewStyle;
boxMainContainerStyle?: ViewStyle;
@@ -84,21 +83,30 @@ export interface TextInputCustomProps
export const Label: React.FC<{
children: string;
- style?: TextStyle;
+ style?: StyleProp;
isRequired?: boolean;
-}> = ({ children, style, isRequired }) => (
+ hovered?: boolean;
+}> = ({ children, style, isRequired, hovered }) => (
-
+
{children}
{!!isRequired && children && (
@@ -123,6 +131,7 @@ export const TextInputCustom = ({
width,
height,
variant = "regular",
+ noBrokenCorners,
name,
control,
defaultValue,
@@ -130,10 +139,10 @@ export const TextInputCustom = ({
subtitle,
labelStyle,
iconSVG,
- noBrokenCorners,
- // isAsterickSign,
hideLabel,
valueModifier,
+ errorStyle,
+ isLoading,
containerStyle,
boxMainContainerStyle,
error,
@@ -141,14 +150,13 @@ export const TextInputCustom = ({
setRef,
...restProps
}: TextInputCustomProps) => {
- // variables
const { field, fieldState } = useController({
name,
control,
rules,
- defaultValue,
});
const inputRef = useRef(null);
+ const [hovered, setHovered] = useState(false);
// Passing ref to parent since I didn't find a pattern to handle generic argument AND forwardRef
useEffect(() => {
if (inputRef.current && setRef) {
@@ -158,7 +166,7 @@ export const TextInputCustom = ({
useEffect(() => {
if (defaultValue) {
- handleChangeText(defaultValue);
+ handleChangeText(defaultValue || "");
}
// handleChangeText changes on every render and we want to call handleChangeText only when default value changes so we disable exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -218,25 +226,35 @@ export const TextInputCustom = ({
);
return (
-
- {variant === "labelOutside" && (
+ setHovered(true)}
+ onHoverOut={() => setHovered(false)}
+ onPress={() => inputRef?.current?.focus()}
+ disabled={disabled}
+ >
+ {variant === "labelOutside" && !hideLabel && (
<>
-
-
+
>
)}
-
({
)}
{!variant ||
- (!["labelOutside", "noCropBorder"].includes(variant) &&
- !hideLabel && (
- inputRef.current?.focus()}>
-
- {label}
-
-
-
- ))}
+ (variant !== "labelOutside" && !hideLabel && (
+ <>
+
+ {label}
+
+
+ >
+ ))}
handleKeyPress({ event, onPressEnter })}
- placeholderTextColor={neutralA3}
+ placeholderTextColor={neutral77}
value={field.value}
style={[styles.textInput, textInputStyle]}
{...restProps}
/>
- <>{children}>
+ {isLoading ? (
+
+ ) : (
+ <>{children}>
+ )}
{error || fieldError}
-
+
);
};
const styles = StyleSheet.create({
- rowEnd: {
- flexDirection: "row",
- justifyContent: "space-between",
- alignItems: "flex-end",
- },
mainContainer: {
alignItems: "flex-start",
paddingHorizontal: 12,
@@ -304,7 +320,7 @@ const styles = StyleSheet.create({
paddingVertical: layout.padding_x1_5,
},
labelText: {
- color: neutral77,
+ color: neutralA3,
},
textInput: {
fontSize: 14,
@@ -317,4 +333,9 @@ const styles = StyleSheet.create({
alignItems: "center",
width: "100%",
},
+ rowEnd: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "flex-end",
+ },
});
diff --git a/packages/screens/FeedNewArticle/FeedNewArticleScreen.tsx b/packages/screens/FeedNewArticle/FeedNewArticleScreen.tsx
index e1f5a4e846..d6ce7073c7 100644
--- a/packages/screens/FeedNewArticle/FeedNewArticleScreen.tsx
+++ b/packages/screens/FeedNewArticle/FeedNewArticleScreen.tsx
@@ -268,31 +268,32 @@ export const FeedNewArticleScreen: ScreenFC<"FeedNewArticle"> = () => {
borderRadius: 12,
}}
/>
- Article content
-
- {/**@ts-ignore error:TS2589: Type instantiation is excessively deep and possibly infinite. */}
- (
-
- )}
- />
+
+ Article content
+
+ (
+
+ )}
+ />
+
);
diff --git a/packages/screens/Organizations/components/ConfigureVotingSection.tsx b/packages/screens/Organizations/components/ConfigureVotingSection.tsx
index 1ab0124e5d..57f8caa5f9 100644
--- a/packages/screens/Organizations/components/ConfigureVotingSection.tsx
+++ b/packages/screens/Organizations/components/ConfigureVotingSection.tsx
@@ -76,7 +76,7 @@ export const ConfigureVotingSection: React.FC = ({
name="days"
- variant="noCropBorder"
+ noBrokenCorners
hideLabel
control={control}
label=""
@@ -89,7 +89,7 @@ export const ConfigureVotingSection: React.FC = ({
name="hours"
- variant="noCropBorder"
+ noBrokenCorners
hideLabel
control={control}
label=""
@@ -103,7 +103,7 @@ export const ConfigureVotingSection: React.FC = ({
name="minutes"
- variant="noCropBorder"
+ noBrokenCorners
hideLabel
control={control}
label=""
diff --git a/packages/screens/Organizations/components/CreateDAOSection.tsx b/packages/screens/Organizations/components/CreateDAOSection.tsx
index 6871ce06fb..7e48beecf2 100644
--- a/packages/screens/Organizations/components/CreateDAOSection.tsx
+++ b/packages/screens/Organizations/components/CreateDAOSection.tsx
@@ -63,43 +63,44 @@ export const CreateDAOSection: React.FC = ({
+ noBrokenCorners
+ variant="labelOutside"
control={control}
- variant="noCropBorder"
label="Organization's name"
placeHolder="Type organization's name here"
name="organizationName"
rules={{ required: true }}
- // isAsterickSign
/>
+ noBrokenCorners
+ variant="labelOutside"
control={control}
- variant="noCropBorder"
label="Associated Teritori Name Service"
placeHolder="your-organization.tori"
name="associatedTeritoriNameService"
rules={{ required: true }}
- // isAsterickSign
/>
+ noBrokenCorners
control={control}
- variant="noCropBorder"
+ variant="labelOutside"
label="Organization's image url"
placeHolder="https://example.com/preview.png"
name="imageUrl"
rules={{ required: true }}
- // isAsterickSign
/>
+ noBrokenCorners
+ variant="labelOutside"
control={control}
- variant="noCropBorder"
label="Organization's description"
placeHolder="Type organization's description here"
name="organizationDescription"
diff --git a/packages/screens/Organizations/components/MemberSettingsSection.tsx b/packages/screens/Organizations/components/MemberSettingsSection.tsx
index c514cc3513..d61fbb698f 100644
--- a/packages/screens/Organizations/components/MemberSettingsSection.tsx
+++ b/packages/screens/Organizations/components/MemberSettingsSection.tsx
@@ -54,11 +54,10 @@ export const MemberSettingsSection: React.FC = ({
name={`members.${index}.addr`}
- variant="noCropBorder"
+ noBrokenCorners
label="Member Address"
hideLabel={index > 0}
control={control}
- // isAsterickSign
rules={{ required: true, validate: validateAddress }}
placeHolder="Account address"
iconSVG={walletInputSVG}
@@ -75,11 +74,10 @@ export const MemberSettingsSection: React.FC = ({
name={`members.${index}.weight`}
- variant="noCropBorder"
+ noBrokenCorners
label="Weight"
hideLabel={index > 0}
control={control}
- // isAsterickSign
rules={{ required: true, pattern: patternOnlyNumbers }}
placeHolder="1"
/>
diff --git a/packages/screens/Organizations/components/TokenSettingsSection.tsx b/packages/screens/Organizations/components/TokenSettingsSection.tsx
index 0dfe358e59..970ae4581d 100644
--- a/packages/screens/Organizations/components/TokenSettingsSection.tsx
+++ b/packages/screens/Organizations/components/TokenSettingsSection.tsx
@@ -56,10 +56,9 @@ export const TokenSettingsSection: React.FC = ({
name="tokenName"
- variant="noCropBorder"
+ noBrokenCorners
label="Token name"
control={control}
- // isAsterickSign
rules={{ required: true }}
placeHolder="My Organization Token"
/>
@@ -68,10 +67,9 @@ export const TokenSettingsSection: React.FC = ({
name="tokenSymbol"
- variant="noCropBorder"
+ noBrokenCorners
label="Token Symbol"
control={control}
- // isAsterickSign
valueModifier={(value) => value.toUpperCase()}
rules={{ required: true, pattern: patternOnlyLetters }}
placeHolder="ABC"
@@ -85,11 +83,10 @@ export const TokenSettingsSection: React.FC = ({
name={`tokenHolders.${index}.address`}
- variant="noCropBorder"
+ noBrokenCorners
label="Token Holders"
hideLabel={index > 0}
control={control}
- // isAsterickSign
rules={{ required: true, validate: validateAddress }}
placeHolder="Account address"
iconSVG={walletInputSVG}
@@ -106,11 +103,10 @@ export const TokenSettingsSection: React.FC = ({
name={`tokenHolders.${index}.balance`}
- variant="noCropBorder"
+ noBrokenCorners
label="Balances"
hideLabel={index > 0}
control={control}
- // isAsterickSign
rules={{ required: true, pattern: patternOnlyNumbers }}
placeHolder="0"
/>