web style
This commit is contained in:
@@ -1,16 +1,17 @@
|
|||||||
import { BlurView } from "expo-blur";
|
import { BlurView } from "expo-blur";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { FlatList, Platform, SectionList, Text, View } from "react-native";
|
import { FlatList, Platform, SectionList, Text, View } from "react-native";
|
||||||
|
import useLayoutType from "../../hooks/useLayoutType";
|
||||||
import CreateLyricsHeader from "../../screens/Writing/components/CreateLyricsHeader";
|
import CreateLyricsHeader from "../../screens/Writing/components/CreateLyricsHeader";
|
||||||
import { Palette } from "../../styles";
|
import { Palette } from "../../styles";
|
||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
|
import { LinearGradient } from "../LinearGradient/LinearGradient";
|
||||||
|
|
||||||
|
const BLUE_SELECTION_GRADIENT = ["#4673F9", "#7023F7"];
|
||||||
|
|
||||||
|
const buildItemKey = (value, category) =>
|
||||||
|
category ? `${category}::${value}` : `${value}`;
|
||||||
|
|
||||||
// Reusable selection list supporting single, multiple and sectioned data.
|
|
||||||
// Variants supported:
|
|
||||||
// - "simple": options are strings
|
|
||||||
// - "titleDescription": options are { title, description }
|
|
||||||
// - "emotion": options are { title, description, color } (uses gradient colors)
|
|
||||||
// - "sectioned": options are sections [{ title, data: [] }] (single per section)
|
|
||||||
const ListSelection = ({
|
const ListSelection = ({
|
||||||
options = [],
|
options = [],
|
||||||
variant = "simple",
|
variant = "simple",
|
||||||
@@ -27,8 +28,9 @@ const ListSelection = ({
|
|||||||
itemOuterStyle,
|
itemOuterStyle,
|
||||||
itemTextStyle,
|
itemTextStyle,
|
||||||
highlightColor = "#F94697",
|
highlightColor = "#F94697",
|
||||||
|
disableHover = false,
|
||||||
}) => {
|
}) => {
|
||||||
// Internal fallback state when not provided by parent
|
// état interne si non contrôlé
|
||||||
const [internalSelected, setInternalSelected] = useState(
|
const [internalSelected, setInternalSelected] = useState(
|
||||||
variant === "sectioned" ? {} : multiple ? [] : null
|
variant === "sectioned" ? {} : multiple ? [] : null
|
||||||
);
|
);
|
||||||
@@ -36,10 +38,18 @@ const ListSelection = ({
|
|||||||
const setSelected =
|
const setSelected =
|
||||||
setSelectedProp !== undefined ? setSelectedProp : setInternalSelected;
|
setSelectedProp !== undefined ? setSelectedProp : setInternalSelected;
|
||||||
|
|
||||||
|
const { isWeb } = useLayoutType();
|
||||||
|
const [hoveredKey, setHoveredKey] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (disableHover && hoveredKey !== null) setHoveredKey(null);
|
||||||
|
}, [disableHover, hoveredKey]);
|
||||||
|
|
||||||
|
// helpers
|
||||||
const valueOf = useMemo(() => {
|
const valueOf = useMemo(() => {
|
||||||
if (typeof getItemValue === "function") return getItemValue;
|
if (typeof getItemValue === "function") return getItemValue;
|
||||||
if (variant === "simple") return (item) => item;
|
if (variant === "simple") return (item) => item;
|
||||||
return (item) => item?.title ?? item; // default to title when present
|
return (item) => item?.title ?? item;
|
||||||
}, [getItemValue, variant]);
|
}, [getItemValue, variant]);
|
||||||
|
|
||||||
const formatValue = (item) =>
|
const formatValue = (item) =>
|
||||||
@@ -55,9 +65,7 @@ const ListSelection = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isSelected = (val, category) => {
|
const isSelected = (val, category) => {
|
||||||
if (variant === "sectioned") {
|
if (variant === "sectioned") return selected?.[category] === val;
|
||||||
return selected?.[category] === val;
|
|
||||||
}
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
const list = Array.isArray(selected) ? selected : [];
|
const list = Array.isArray(selected) ? selected : [];
|
||||||
return list.some((v) => v === val);
|
return list.some((v) => v === val);
|
||||||
@@ -67,6 +75,7 @@ const ListSelection = ({
|
|||||||
|
|
||||||
const toggleSelect = (item, category) => {
|
const toggleSelect = (item, category) => {
|
||||||
const val = valueOf(item);
|
const val = valueOf(item);
|
||||||
|
|
||||||
if (variant === "sectioned") {
|
if (variant === "sectioned") {
|
||||||
const current = selected && typeof selected === "object" ? selected : {};
|
const current = selected && typeof selected === "object" ? selected : {};
|
||||||
const next = { ...current };
|
const next = { ...current };
|
||||||
@@ -79,19 +88,16 @@ const ListSelection = ({
|
|||||||
if (multiple) {
|
if (multiple) {
|
||||||
const list = Array.isArray(selected) ? selected : [];
|
const list = Array.isArray(selected) ? selected : [];
|
||||||
const exists = list.some((v) => v === val);
|
const exists = list.some((v) => v === val);
|
||||||
if (exists) {
|
if (exists) setSelected(list.filter((v) => v !== val));
|
||||||
setSelected(list.filter((v) => v !== val));
|
else if (!maxSelection || list.length < maxSelection)
|
||||||
} else {
|
setSelected([...list, formatValue(item)]);
|
||||||
if (!maxSelection || list.length < maxSelection) {
|
|
||||||
setSelected([...list, formatValue(item)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (selected === val) setSelected(null);
|
if (extractSelectedComparable(selected) === val) setSelected(null);
|
||||||
else setSelected(formatValue(item));
|
else setSelected(formatValue(item));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// contenus élémentaires : toujours encapsuler le texte dans <Text>
|
||||||
const renderSimpleContent = (label) => (
|
const renderSimpleContent = (label) => (
|
||||||
<View style={{ minHeight: 40, justifyContent: "center" }}>
|
<View style={{ minHeight: 40, justifyContent: "center" }}>
|
||||||
<Text
|
<Text
|
||||||
@@ -103,7 +109,7 @@ const ListSelection = ({
|
|||||||
...itemTextStyle,
|
...itemTextStyle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{typeof label === "string" ? label : String(label)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -118,14 +124,36 @@ const ListSelection = ({
|
|||||||
...itemTextStyle,
|
...itemTextStyle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text style={{ fontFamily: FONT_FAMILY.InterBold }}>{item?.title}</Text>{" "}
|
<Text style={{ fontFamily: FONT_FAMILY.InterBold }}>{item?.title}</Text>
|
||||||
: {item?.description}
|
<Text>{` : ${item?.description ?? ""}`}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// applique le gradient bleu UNIQUEMENT sur web et quand sélectionné
|
||||||
|
const withWebBlueGradientIfSelected = (content, sel) => {
|
||||||
|
if (!isWeb || !sel) return content;
|
||||||
|
// wrap dans un View pour éviter texte brut direct sous le gradient (compat RN Web)
|
||||||
|
return (
|
||||||
|
<LinearGradient
|
||||||
|
colors={BLUE_SELECTION_GRADIENT}
|
||||||
|
start={{ x: 0, y: 0 }}
|
||||||
|
end={{ x: 1, y: 0 }}
|
||||||
|
locations={[0, 1]}
|
||||||
|
style={{
|
||||||
|
borderRadius: 14,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 8,
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View>{content}</View>
|
||||||
|
</LinearGradient>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============ SECTIONED ============
|
||||||
if (variant === "sectioned") {
|
if (variant === "sectioned") {
|
||||||
// Sectioned list: options as [{ title, data: [] }]
|
|
||||||
return (
|
return (
|
||||||
<SectionList
|
<SectionList
|
||||||
sections={options}
|
sections={options}
|
||||||
@@ -135,22 +163,49 @@ const ListSelection = ({
|
|||||||
const cat = section?.title;
|
const cat = section?.title;
|
||||||
const val = valueOf(item);
|
const val = valueOf(item);
|
||||||
const sel = isSelected(val, cat);
|
const sel = isSelected(val, cat);
|
||||||
|
const itemKey = buildItemKey(String(val ?? ""), cat);
|
||||||
|
const isHovered = isWeb && !disableHover && hoveredKey === itemKey;
|
||||||
|
const showHoverOutline = isHovered && !sel;
|
||||||
|
|
||||||
|
const baseContent = renderSimpleContent(item);
|
||||||
|
const headerContainerStyle = {
|
||||||
|
borderWidth: 0,
|
||||||
|
borderColor: "transparent",
|
||||||
|
borderRadius: 14,
|
||||||
|
...itemContainerStyle,
|
||||||
|
};
|
||||||
|
if (sel && isWeb)
|
||||||
|
headerContainerStyle.backgroundColor = "transparent";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[{ position: "relative" }, itemOuterStyle]}>
|
<View
|
||||||
|
style={[{ position: "relative" }, itemOuterStyle]}
|
||||||
|
onMouseEnter={
|
||||||
|
isWeb && !disableHover
|
||||||
|
? () => setHoveredKey(itemKey)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onMouseLeave={
|
||||||
|
isWeb && !disableHover ? () => setHoveredKey(null) : undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
<CreateLyricsHeader
|
<CreateLyricsHeader
|
||||||
onPress={() => toggleSelect(item, cat)}
|
onPress={() => toggleSelect(item, cat)}
|
||||||
tint={sel ? "default" : "dark"}
|
tint={sel ? "default" : "dark"}
|
||||||
colors={[Palette.tran, Palette.tran]}
|
colors={[Palette.tran, Palette.tran]}
|
||||||
containerStyle={{
|
showBorder={!sel}
|
||||||
borderWidth: 0,
|
disableBlur={sel && isWeb}
|
||||||
borderColor: "transparent",
|
blurViewStyle={
|
||||||
borderRadius: 14,
|
sel && isWeb
|
||||||
...itemContainerStyle,
|
? { paddingHorizontal: 0, paddingVertical: 0 }
|
||||||
}}
|
: undefined
|
||||||
|
}
|
||||||
|
containerStyle={headerContainerStyle}
|
||||||
>
|
>
|
||||||
{renderSimpleContent(item)}
|
{withWebBlueGradientIfSelected(baseContent, sel)}
|
||||||
</CreateLyricsHeader>
|
</CreateLyricsHeader>
|
||||||
{sel && (
|
|
||||||
|
{showHoverOutline && (
|
||||||
<View
|
<View
|
||||||
pointerEvents="none"
|
pointerEvents="none"
|
||||||
style={{
|
style={{
|
||||||
@@ -198,10 +253,12 @@ const ListSelection = ({
|
|||||||
</BlurView>
|
</BlurView>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
keyExtractor={(item, idx) => `${valueOf(item)}-${idx}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============ FLAT (simple/titleDescription/emotion) ============
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
data={options}
|
data={options}
|
||||||
@@ -211,7 +268,8 @@ const ListSelection = ({
|
|||||||
const val = valueOf(item);
|
const val = valueOf(item);
|
||||||
const sel = isSelected(val);
|
const sel = isSelected(val);
|
||||||
const useEmotionColors = variant === "emotion";
|
const useEmotionColors = variant === "emotion";
|
||||||
// For emotion variant, hide the left color when selected
|
|
||||||
|
// pour "emotion", on masque le bord gauche si sélectionné
|
||||||
const borderColors = useEmotionColors
|
const borderColors = useEmotionColors
|
||||||
? sel
|
? sel
|
||||||
? [Palette.tran, Palette.tran]
|
? [Palette.tran, Palette.tran]
|
||||||
@@ -219,27 +277,53 @@ const ListSelection = ({
|
|||||||
: [Palette.tran, Palette.tran];
|
: [Palette.tran, Palette.tran];
|
||||||
const tint = useEmotionColors ? "dark" : sel ? "default" : "dark";
|
const tint = useEmotionColors ? "dark" : sel ? "default" : "dark";
|
||||||
|
|
||||||
|
const itemKey = buildItemKey(String(val ?? ""));
|
||||||
|
const isHovered = isWeb && !disableHover && hoveredKey === itemKey;
|
||||||
|
const showHoverOutline = isHovered && !sel;
|
||||||
|
|
||||||
|
const baseContent =
|
||||||
|
variant === "simple"
|
||||||
|
? renderSimpleContent(item)
|
||||||
|
: renderTitleDescriptionContent(item);
|
||||||
|
|
||||||
|
const headerContainerStyle = {
|
||||||
|
borderWidth: 0,
|
||||||
|
borderColor: "transparent",
|
||||||
|
borderRadius: 14,
|
||||||
|
...itemContainerStyle,
|
||||||
|
};
|
||||||
|
if (sel && isWeb) headerContainerStyle.backgroundColor = "transparent";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[{ position: "relative" }, itemOuterStyle]}>
|
<View
|
||||||
|
style={[{ position: "relative" }, itemOuterStyle]}
|
||||||
|
onMouseEnter={
|
||||||
|
isWeb && !disableHover ? () => setHoveredKey(itemKey) : undefined
|
||||||
|
}
|
||||||
|
onMouseLeave={
|
||||||
|
isWeb && !disableHover ? () => setHoveredKey(null) : undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
<CreateLyricsHeader
|
<CreateLyricsHeader
|
||||||
colors={borderColors}
|
colors={borderColors} // mobile: rendu d’avant conservé
|
||||||
tint={tint}
|
tint={tint}
|
||||||
onPress={() => toggleSelect(item)}
|
onPress={() => toggleSelect(item)}
|
||||||
gradientProps={
|
gradientProps={
|
||||||
useEmotionColors && !sel ? { locations: [0.24, 1] } : undefined
|
useEmotionColors && !sel ? { locations: [0.24, 1] } : undefined
|
||||||
}
|
}
|
||||||
containerStyle={{
|
showBorder={!sel} // mobile: bordure d’origine
|
||||||
borderWidth: 0,
|
disableBlur={sel && isWeb} // web: pas de blur si gradient
|
||||||
borderColor: "transparent",
|
blurViewStyle={
|
||||||
borderRadius: 14,
|
sel && isWeb
|
||||||
...itemContainerStyle,
|
? { paddingHorizontal: 0, paddingVertical: 0 }
|
||||||
}}
|
: undefined
|
||||||
|
}
|
||||||
|
containerStyle={headerContainerStyle}
|
||||||
>
|
>
|
||||||
{variant === "simple"
|
{withWebBlueGradientIfSelected(baseContent, sel)}
|
||||||
? renderSimpleContent(item)
|
|
||||||
: renderTitleDescriptionContent(item)}
|
|
||||||
</CreateLyricsHeader>
|
</CreateLyricsHeader>
|
||||||
{sel && (
|
|
||||||
|
{showHoverOutline && (
|
||||||
<View
|
<View
|
||||||
pointerEvents="none"
|
pointerEvents="none"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { View } from "react-native";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import CreateLyricsHeader from "./components/CreateLyricsHeader";
|
import { View } from "react-native";
|
||||||
import { EMOTION_CONVEY } from "../../data/data";
|
|
||||||
import ItemContainer from "../../components/ItemContainer/ItemContainer";
|
import ItemContainer from "../../components/ItemContainer/ItemContainer";
|
||||||
import ListSelection from "../../components/ListSelection/ListSelection";
|
import ListSelection from "../../components/ListSelection/ListSelection";
|
||||||
|
import { EMOTION_CONVEY } from "../../data/data";
|
||||||
|
import CreateLyricsHeader from "./components/CreateLyricsHeader";
|
||||||
|
|
||||||
const EmotionConvey = ({
|
const EmotionConvey = ({
|
||||||
selected: selectedProp,
|
selected: selectedProp,
|
||||||
@@ -29,6 +29,7 @@ const EmotionConvey = ({
|
|||||||
>
|
>
|
||||||
<ItemContainer height={containerLayout?.height}>
|
<ItemContainer height={containerLayout?.height}>
|
||||||
<ListSelection
|
<ListSelection
|
||||||
|
disableHover
|
||||||
options={EMOTION_CONVEY}
|
options={EMOTION_CONVEY}
|
||||||
variant="emotion"
|
variant="emotion"
|
||||||
selected={selected}
|
selected={selected}
|
||||||
|
|||||||
@@ -66,29 +66,31 @@ const CreateLyricsHeader = ({
|
|||||||
...blurViewStyle,
|
...blurViewStyle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{title && (
|
<>
|
||||||
<Text
|
{title && (
|
||||||
style={{
|
<Text
|
||||||
fontSize: 22,
|
style={{
|
||||||
color: Palette.white,
|
fontSize: 22,
|
||||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
color: Palette.white,
|
||||||
}}
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||||
>
|
}}
|
||||||
{title}
|
>
|
||||||
</Text>
|
{title}
|
||||||
)}
|
</Text>
|
||||||
{subTitle && (
|
)}
|
||||||
<Text
|
{subTitle && (
|
||||||
style={{
|
<Text
|
||||||
fontSize: 12,
|
style={{
|
||||||
color: Palette.white,
|
fontSize: 12,
|
||||||
fontFamily: FONT_FAMILY.InterRegular,
|
color: Palette.white,
|
||||||
}}
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
>
|
}}
|
||||||
{subTitle}
|
>
|
||||||
</Text>
|
{subTitle}
|
||||||
)}
|
</Text>
|
||||||
{children}
|
)}
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<BlurView
|
<BlurView
|
||||||
@@ -104,29 +106,31 @@ const CreateLyricsHeader = ({
|
|||||||
// Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
// Platform.OS !== "ios" ? "dimezisBlurView" : "none"
|
||||||
// }
|
// }
|
||||||
>
|
>
|
||||||
{title && (
|
<>
|
||||||
<Text
|
{title && (
|
||||||
style={{
|
<Text
|
||||||
fontSize: 22,
|
style={{
|
||||||
color: Palette.white,
|
fontSize: 22,
|
||||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
color: Palette.white,
|
||||||
}}
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||||
>
|
}}
|
||||||
{title}
|
>
|
||||||
</Text>
|
{title}
|
||||||
)}
|
</Text>
|
||||||
{subTitle && (
|
)}
|
||||||
<Text
|
{subTitle && (
|
||||||
style={{
|
<Text
|
||||||
fontSize: 12,
|
style={{
|
||||||
color: Palette.white,
|
fontSize: 12,
|
||||||
fontFamily: FONT_FAMILY.InterRegular,
|
color: Palette.white,
|
||||||
}}
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
>
|
}}
|
||||||
{subTitle}
|
>
|
||||||
</Text>
|
{subTitle}
|
||||||
)}
|
</Text>
|
||||||
{children}
|
)}
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
</BlurView>
|
</BlurView>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { View, Text, TextInput } from "react-native";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Text, TextInput, View } from "react-native";
|
||||||
import { Palette } from "../../../styles";
|
import { Palette } from "../../../styles";
|
||||||
import { FONT_FAMILY } from "../../../styles/Fonts";
|
import { FONT_FAMILY } from "../../../styles/Fonts";
|
||||||
|
|
||||||
@@ -17,44 +17,46 @@ const CustomInput = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<View style={{ gap: 8 }} onLayout={onLayout}>
|
<View style={{ gap: 8 }} onLayout={onLayout}>
|
||||||
{label && (
|
<>
|
||||||
<Text
|
{label && (
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.InterMedium,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<View
|
||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
backgroundColor: Palette.white,
|
||||||
color: Palette.white,
|
height,
|
||||||
fontFamily: FONT_FAMILY.InterMedium,
|
padding: 12,
|
||||||
|
borderRadius: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
<TextInput
|
||||||
</Text>
|
placeholder={placeholder}
|
||||||
)}
|
placeholderTextColor={Palette.grayMid}
|
||||||
<View
|
value={value}
|
||||||
style={{
|
onChangeText={setValue}
|
||||||
backgroundColor: Palette.white,
|
style={{
|
||||||
height,
|
height: "100%",
|
||||||
padding: 12,
|
fontSize: 16,
|
||||||
borderRadius: 12,
|
color: Palette.black,
|
||||||
}}
|
fontFamily: FONT_FAMILY.InterRegularItalic,
|
||||||
>
|
}}
|
||||||
<TextInput
|
multiline={multiline}
|
||||||
placeholder={placeholder}
|
numberOfLines={multiline ? undefined : 1}
|
||||||
placeholderTextColor={Palette.grayMid}
|
maxLength={maxLength}
|
||||||
value={value}
|
textAlignVertical={multiline ? "top" : "center"}
|
||||||
onChangeText={setValue}
|
onFocus={onFocus}
|
||||||
style={{
|
onBlur={onBlur}
|
||||||
height: "100%",
|
/>
|
||||||
fontSize: 16,
|
</View>
|
||||||
color: Palette.black,
|
</>
|
||||||
fontFamily: FONT_FAMILY.InterRegularItalic,
|
|
||||||
}}
|
|
||||||
multiline={multiline}
|
|
||||||
numberOfLines={multiline ? undefined : 1}
|
|
||||||
maxLength={maxLength}
|
|
||||||
textAlignVertical={multiline ? "top" : "center"}
|
|
||||||
onFocus={onFocus}
|
|
||||||
onBlur={onBlur}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user