react-bootstrap#FloatingLabel TypeScript Examples
The following examples show how to use
react-bootstrap#FloatingLabel.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
VoteModal = ({ show, onHide, proposalId, availableVotes }: VoteModalProps) => {
const { castVote, castVoteState } = useCastVote();
const { castVoteWithReason, castVoteWithReasonState } = useCastVoteWithReason();
const [vote, setVote] = useState<Vote>();
const [voteReason, setVoteReason] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isVoteSucessful, setIsVoteSuccessful] = useState(false);
const [isVoteFailed, setIsVoteFailed] = useState(false);
const [failureCopy, setFailureCopy] = useState<ReactNode>('');
const [errorMessage, setErrorMessage] = useState<ReactNode>('');
const getVoteErrorMessage = (error: string | undefined) => {
if (error?.match(/voter already voted/)) {
return <Trans>User Already Voted</Trans>;
}
return error;
};
const handleVoteStateChange = useCallback((state: TransactionStatus) => {
switch (state.status) {
case 'None':
setIsLoading(false);
break;
case 'Mining':
setIsLoading(true);
break;
case 'Success':
setIsLoading(false);
setIsVoteSuccessful(true);
break;
case 'Fail':
setFailureCopy(<Trans>Transaction Failed</Trans>);
setErrorMessage(state?.errorMessage || <Trans>Please try again.</Trans>);
setIsLoading(false);
setIsVoteFailed(true);
break;
case 'Exception':
setFailureCopy(<Trans>Error</Trans>);
setErrorMessage(
getVoteErrorMessage(state?.errorMessage) || <Trans>Please try again.</Trans>,
);
setIsLoading(false);
setIsVoteFailed(true);
break;
}
}, []);
// Cast vote transaction state hook
useEffect(() => {
handleVoteStateChange(castVoteState);
}, [castVoteState, handleVoteStateChange]);
// Cast vote with reason transaction state hook
useEffect(() => {
handleVoteStateChange(castVoteWithReasonState);
}, [castVoteWithReasonState, handleVoteStateChange]);
// Auto close the modal after a transaction completes succesfully
// Leave failed transaction up until user closes manually to allow for debugging
useEffect(() => {
if (isVoteSucessful) {
setTimeout(onHide, POST_SUCESSFUL_VOTE_MODAL_CLOSE_TIME_MS);
}
}, [isVoteSucessful, onHide]);
// If show is false (i.e. on hide) reset failure related state variables
useEffect(() => {
if (show) {
return;
}
setIsVoteFailed(false);
}, [show]);
const voteModalContent = (
<>
{isVoteSucessful && (
<div className={classes.transactionStatus}>
<p>
<Trans>
You've successfully voted on on prop {i18n.number(parseInt(proposalId || '0'))}
</Trans>
</p>
<div className={classes.voteSuccessBody}>
<Trans>Thank you for voting.</Trans>
</div>
</div>
)}
{isVoteFailed && (
<div className={classes.transactionStatus}>
<p className={classes.voteFailureTitle}>
<Trans>There was an error voting for your account.</Trans>
</p>
<div className={classes.voteFailureBody}>
{failureCopy}: <span className={classes.voteFailureErrorMessage}>{errorMessage}</span>
</div>
</div>
)}
{!isVoteFailed && !isVoteSucessful && (
<div className={clsx(classes.votingButtonsWrapper, isLoading ? classes.disabled : '')}>
<div onClick={() => setVote(Vote.FOR)}>
<NavBarButton
buttonText={
availableVotes > 1 ? (
<Trans>
Cast {i18n.number(availableVotes)} votes for Prop{' '}
{i18n.number(parseInt(proposalId || '0'))}
</Trans>
) : (
<Trans>Cast 1 vote for Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>
)
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.FOR
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<div onClick={() => setVote(Vote.AGAINST)}>
<NavBarButton
buttonText={
availableVotes > 1 ? (
<Trans>
Cast {i18n.number(availableVotes)} votes against Prop{' '}
{i18n.number(parseInt(proposalId || '0'))}
</Trans>
) : (
<Trans>Cast 1 vote against Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>
)
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.AGAINST
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<div onClick={() => setVote(Vote.ABSTAIN)}>
<NavBarButton
buttonText={
<Trans>
Abstain from voting on Prop {i18n.number(parseInt(proposalId || '0'))}
</Trans>
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.ABSTAIN
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<FloatingLabel controlId="reasonTextarea" label={<Trans>Reason (Optional)</Trans>}>
<FormControl
as="textarea"
placeholder={
i18n.locale === 'en' ? `Reason for voting ${Vote[vote ?? Vote.FOR]}` : ''
}
value={voteReason}
onChange={e => setVoteReason(e.target.value)}
className={classes.voteReasonTextarea}
/>
</FloatingLabel>
<br />
<Button
onClick={() => {
if (vote === undefined || !proposalId || isLoading) {
return;
}
setIsLoading(true);
if (voteReason.trim() === '') {
castVote(proposalId, vote);
} else {
castVoteWithReason(proposalId, vote, voteReason);
}
}}
className={vote === undefined ? classes.submitBtnDisabled : classes.submitBtn}
>
{isLoading ? <Spinner animation="border" /> : <Trans>Submit Vote</Trans>}
</Button>
</div>
)}
</>
);
// On modal dismiss, reset non-success state
const resetNonSuccessStateAndHideModal = () => {
setIsLoading(false);
setIsVoteFailed(false);
setErrorMessage('');
setFailureCopy('');
onHide();
};
return (
<>
{show && (
<Modal
onDismiss={resetNonSuccessStateAndHideModal}
title={<Trans>Vote on Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>}
content={voteModalContent}
/>
)}
</>
);
}
Example #2
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
Playground: React.FC = () => {
const [nounSvgs, setNounSvgs] = useState<string[]>();
const [traits, setTraits] = useState<Trait[]>();
const [modSeed, setModSeed] = useState<{ [key: string]: number }>();
const [initLoad, setInitLoad] = useState<boolean>(true);
const [displayNoun, setDisplayNoun] = useState<boolean>(false);
const [indexOfNounToDisplay, setIndexOfNounToDisplay] = useState<number>();
const [selectIndexes, setSelectIndexes] = useState<Record<string, number>>({});
const [pendingTrait, setPendingTrait] = useState<PendingCustomTrait>();
const [isPendingTraitValid, setPendingTraitValid] = useState<boolean>();
const customTraitFileRef = useRef<HTMLInputElement>(null);
const generateNounSvg = React.useCallback(
(amount: number = 1) => {
for (let i = 0; i < amount; i++) {
const seed = { ...getRandomNounSeed(), ...modSeed };
const { parts, background } = getNounData(seed);
const svg = buildSVG(parts, encoder.data.palette, background);
setNounSvgs(prev => {
return prev ? [svg, ...prev] : [svg];
});
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[pendingTrait, modSeed],
);
useEffect(() => {
const traitTitles = ['background', 'body', 'accessory', 'head', 'glasses'];
const traitNames = [
['cool', 'warm'],
...Object.values(ImageData.images).map(i => {
return i.map(imageData => imageData.filename);
}),
];
setTraits(
traitTitles.map((value, index) => {
return {
title: value,
traitNames: traitNames[index],
};
}),
);
if (initLoad) {
generateNounSvg(8);
setInitLoad(false);
}
}, [generateNounSvg, initLoad]);
const traitOptions = (trait: Trait) => {
return Array.from(Array(trait.traitNames.length + 1)).map((_, index) => {
const traitName = trait.traitNames[index - 1];
const parsedTitle = index === 0 ? `Random` : parseTraitName(traitName);
return (
<option key={index} value={traitName}>
{parsedTitle}
</option>
);
});
};
const traitButtonHandler = (trait: Trait, traitIndex: number) => {
setModSeed(prev => {
// -1 traitIndex = random
if (traitIndex < 0) {
let state = { ...prev };
delete state[trait.title];
return state;
}
return {
...prev,
[trait.title]: traitIndex,
};
});
};
const resetTraitFileUpload = () => {
if (customTraitFileRef.current) {
customTraitFileRef.current.value = '';
}
};
let pendingTraitErrorTimeout: NodeJS.Timeout;
const setPendingTraitInvalid = () => {
setPendingTraitValid(false);
resetTraitFileUpload();
pendingTraitErrorTimeout = setTimeout(() => {
setPendingTraitValid(undefined);
}, 5_000);
};
const validateAndSetCustomTrait = (file: File | undefined) => {
if (pendingTraitErrorTimeout) {
clearTimeout(pendingTraitErrorTimeout);
}
if (!file) {
return;
}
const reader = new FileReader();
reader.onload = e => {
try {
const buffer = Buffer.from(e?.target?.result!);
const png = PNG.sync.read(buffer);
if (png.width !== 32 || png.height !== 32) {
throw new Error('Image must be 32x32');
}
const filename = file.name?.replace('.png', '') || 'custom';
const data = encoder.encodeImage(filename, {
width: png.width,
height: png.height,
rgbaAt: (x: number, y: number) => {
const idx = (png.width * y + x) << 2;
const [r, g, b, a] = [
png.data[idx],
png.data[idx + 1],
png.data[idx + 2],
png.data[idx + 3],
];
return {
r,
g,
b,
a,
};
},
});
setPendingTrait({
data,
filename,
type: DEFAULT_TRAIT_TYPE,
});
setPendingTraitValid(true);
} catch (error) {
setPendingTraitInvalid();
}
};
reader.readAsArrayBuffer(file);
};
const uploadCustomTrait = () => {
const { type, data, filename } = pendingTrait || {};
if (type && data && filename) {
const images = ImageData.images as Record<string, EncodedImage[]>;
images[type].unshift({
filename,
data,
});
const title = traitKeyToTitle[type];
const trait = traits?.find(t => t.title === title);
resetTraitFileUpload();
setPendingTrait(undefined);
setPendingTraitValid(undefined);
traitButtonHandler(trait!, 0);
setSelectIndexes({
...selectIndexes,
[title]: 0,
});
}
};
return (
<>
{displayNoun && indexOfNounToDisplay !== undefined && nounSvgs && (
<NounModal
onDismiss={() => {
setDisplayNoun(false);
}}
svg={nounSvgs[indexOfNounToDisplay]}
/>
)}
<Container fluid="lg">
<Row>
<Col lg={10} className={classes.headerRow}>
<span>
<Trans>Explore</Trans>
</span>
<h1>
<Trans>Playground</Trans>
</h1>
<p>
<Trans>
The playground was built using the {nounsProtocolLink}. Noun's traits are determined
by the Noun Seed. The seed was generated using {nounsAssetsLink} and rendered using
the {nounsSDKLink}.
</Trans>
</p>
</Col>
</Row>
<Row>
<Col lg={3}>
<Col lg={12}>
<Button
onClick={() => {
generateNounSvg();
}}
className={classes.primaryBtn}
>
<Trans>Generate Nouns</Trans>
</Button>
</Col>
<Row>
{traits &&
traits.map((trait, index) => {
return (
<Col lg={12} xs={6}>
<Form className={classes.traitForm}>
<FloatingLabel
controlId="floatingSelect"
label={traitKeyToLocalizedTraitKeyFirstLetterCapitalized(trait.title)}
key={index}
className={classes.floatingLabel}
>
<Form.Select
aria-label="Floating label select example"
className={classes.traitFormBtn}
value={trait.traitNames[selectIndexes?.[trait.title]] ?? -1}
onChange={e => {
let index = e.currentTarget.selectedIndex;
traitButtonHandler(trait, index - 1); // - 1 to account for 'random'
setSelectIndexes({
...selectIndexes,
[trait.title]: index - 1,
});
}}
>
{traitOptions(trait)}
</Form.Select>
</FloatingLabel>
</Form>
</Col>
);
})}
</Row>
<label style={{ margin: '1rem 0 .25rem 0' }} htmlFor="custom-trait-upload">
<Trans>Upload Custom Trait</Trans>
<OverlayTrigger
trigger="hover"
placement="top"
overlay={
<Popover>
<div style={{ padding: '0.25rem' }}>
<Trans>Only 32x32 PNG images are accepted</Trans>
</div>
</Popover>
}
>
<Image
style={{ margin: '0 0 .25rem .25rem' }}
src={InfoIcon}
className={classes.voteIcon}
/>
</OverlayTrigger>
</label>
<Form.Control
type="file"
id="custom-trait-upload"
accept="image/PNG"
isValid={isPendingTraitValid}
isInvalid={isPendingTraitValid === false}
ref={customTraitFileRef}
className={classes.fileUpload}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
validateAndSetCustomTrait(e.target.files?.[0])
}
/>
{pendingTrait && (
<>
<FloatingLabel label="Custom Trait Type" className={classes.floatingLabel}>
<Form.Select
aria-label="Custom Trait Type"
className={classes.traitFormBtn}
onChange={e => setPendingTrait({ ...pendingTrait, type: e.target.value })}
>
{Object.entries(traitKeyToTitle).map(([key, title]) => (
<option value={key}>{capitalizeFirstLetter(title)}</option>
))}
</Form.Select>
</FloatingLabel>
<Button onClick={() => uploadCustomTrait()} className={classes.primaryBtn}>
<Trans>Upload</Trans>
</Button>
</>
)}
<p className={classes.nounYearsFooter}>
<Trans>
You've generated{' '}
{i18n.number(parseInt(nounSvgs ? (nounSvgs.length / 365).toFixed(2) : '0'))} years
worth of Nouns
</Trans>
</p>
</Col>
<Col lg={9}>
<Row>
{nounSvgs &&
nounSvgs.map((svg, i) => {
return (
<Col xs={4} lg={3} key={i}>
<div
onClick={() => {
setIndexOfNounToDisplay(i);
setDisplayNoun(true);
}}
>
<Noun
imgPath={`data:image/svg+xml;base64,${btoa(svg)}`}
alt="noun"
className={classes.nounImg}
wrapperClassName={classes.nounWrapper}
/>
</div>
</Col>
);
})}
</Row>
</Col>
</Row>
</Container>
</>
);
}