Skip to content

Commit

Permalink
refactor: reuse input and tag input components from react-kit (#1083)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertfolch-redeemeum authored May 28, 2024
1 parent 5efe5a1 commit d2ed435
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 193 deletions.
5 changes: 4 additions & 1 deletion config-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ module.exports = {
util: require.resolve("util/")
};

config.ignoreWarnings = [/Failed to parse source map/];
config.ignoreWarnings = [
/Failed to parse source map/,
/Critical dependency: Accessing import\.meta directly is unsupported \(only property access is supported\)/
];

return config;
},
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"dependencies": {
"@apollo/client": "^3.8.1",
"@bosonprotocol/chat-sdk": "^1.3.1-alpha.9",
"@bosonprotocol/react-kit": "^0.31.1",
"@bosonprotocol/react-kit": "^0.32.0-alpha.1",
"@davatar/react": "^1.10.4",
"@ethersproject/address": "^5.6.1",
"@ethersproject/units": "^5.7.0",
Expand Down
57 changes: 7 additions & 50 deletions src/components/form/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,14 @@
import { ClearButton } from "components/ui/ClearButton";
import { Grid } from "components/ui/Grid";
import { BaseInput } from "@bosonprotocol/react-kit";
import { useField, useFormikContext } from "formik";
import { forwardRef, useMemo } from "react";
import styled from "styled-components";
import { forwardRef } from "react";
import { inputTheme } from "theme";

import Error from "./Error";
import { FieldInput } from "./Field.styles";
import type { InputProps } from "./types";
const StyledFieldInput = styled(FieldInput)`
padding-right: calc(1rem + 12px);
`;
const StyledClearButton = styled(ClearButton)`
top: 1px;
height: calc(100% - 4px);
margin-left: 0;
`;
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ name, isClearable, ...props }, ref) => {
const { status, setFieldValue } = useFormikContext();
const [field, meta] = useField(name);
const errorText = meta.error || status?.[name];
const errorMessage = errorText && meta.touched ? errorText : "";
const displayError =
typeof errorMessage === typeof "string" && errorMessage !== "";
const InputComponent = useMemo(() => {
return isClearable ? (
<Grid style={{ position: "relative" }}>
<StyledFieldInput
error={errorMessage}
{...field}
{...props}
ref={ref}
/>
{isClearable && (
<StyledClearButton onClick={() => setFieldValue(name, "")} />
)}
</Grid>
) : (
<FieldInput error={errorMessage} {...field} {...props} ref={ref} />
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [errorMessage, field, isClearable, name, props, ref]);
return (
<>
{InputComponent}
<Error
display={!props.hideError && displayError}
message={errorMessage}
/>
</>
);
}
);

export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
return <BaseInput {...props} ref={ref} theme={inputTheme} />;
});

export const InputError = ({ name }: Pick<InputProps, "name">) => {
const { status } = useFormikContext();
Expand Down
122 changes: 4 additions & 118 deletions src/components/form/TagsInput.tsx
Original file line number Diff line number Diff line change
@@ -1,122 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useField, useFormikContext } from "formik";
import { KeyReturn } from "phosphor-react";
import { useEffect, useRef } from "react";
import { BaseTagsInput, BaseTagsInputProps } from "@bosonprotocol/react-kit";
import { inputTheme } from "theme";

import { Grid } from "../ui/Grid";
import { Typography } from "../ui/Typography";
import Error from "./Error";
import { FieldInput } from "./Field.styles";
import {
Close,
Helper,
TagContainer,
TagWrapper
} from "./styles/TagsInput.styles";
import { TagsProps } from "./types";

const TagsInput = ({
name,
placeholder,
onAddTag,
onRemoveTag,
compareTags = (tagA: string, tagB: string) =>
tagA.toLowerCase() === tagB.toLowerCase(),
transform = (tag: string) => tag,
label
}: TagsProps) => {
const { validateForm } = useFormikContext();
const [field, meta, helpers] = useField<string[]>(name);
const tags = field.value || [];

const errorMessage = meta.error && meta.touched ? meta.error : "";
const displayError =
typeof errorMessage === typeof "string" && errorMessage !== "";

const handleBlur = () => {
if (!meta.touched) {
helpers.setTouched(true);
}
};

function handleKeyDown(event: any) {
if (event.key !== "Enter") return;
event.preventDefault();
const value: string = event.target.value;
if (!value.trim()) return;
event.target.value = "";
if (!meta.touched) {
helpers.setTouched(true);
}

if (!tags.find((tag) => compareTags(tag, value))) {
const transformedValue = transform(value);
const newTags = [...tags, transformedValue];
helpers.setValue(newTags);
onAddTag?.(transformedValue);
}
}

function removeTag(index: number) {
const filteredTags = tags.filter((_, i) => i !== index);
helpers.setValue(filteredTags);
if (!meta.touched) {
helpers.setTouched(true);
}
onRemoveTag?.(tags[index]);
}
useEffect(() => {
validateForm();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [field.value]);
const labelRef = useRef<HTMLDivElement>(null);
const hitEnterWidth = useRef<HTMLDivElement>(null);
return (
<>
<Grid gap="0.5rem" alignItems="center">
{label && (
<Typography data-label ref={labelRef}>
{label}
</Typography>
)}
<TagContainer>
<FieldInput
onKeyDown={handleKeyDown}
type="text"
placeholder={placeholder || "Choose tags..."}
name={name}
onBlur={handleBlur}
error={errorMessage}
{...(hitEnterWidth.current?.clientWidth && {
style: {
paddingRight: `calc(${hitEnterWidth.current.clientWidth}px + 1rem)`
}
})}
/>
<Helper ref={hitEnterWidth}>
Hit Enter <KeyReturn size={13} />
</Helper>
</TagContainer>
</Grid>
<TagContainer>
{label && (
<div
style={{
visibility: "hidden",
width: labelRef.current?.clientWidth
}}
/>
)}
{tags.map((tag: string, index: number) => (
<TagWrapper key={`tags-wrapper_${tag}`}>
<span className="text tag">{tag}</span>
<Close onClick={() => removeTag(index)}>&times;</Close>
</TagWrapper>
))}
</TagContainer>
<Error display={displayError} message={errorMessage} />{" "}
</>
);
const TagsInput = (props: Omit<BaseTagsInputProps, "theme">) => {
return <BaseTagsInput {...props} theme={inputTheme} />;
};

export default TagsInput;
6 changes: 2 additions & 4 deletions src/components/header/accountDrawer/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,14 @@ interface IconButtonProps
type IconBlockProps = React.ComponentPropsWithoutRef<"a" | "button">;

const IconBlock = forwardRef<
(HTMLAnchorElement | HTMLDivElement) & { color: string },
IconBlockProps
HTMLAnchorElement | HTMLDivElement,
IconBlockProps & { color: string }
>(function IconBlock(props, ref) {
const $color = props.color;
if ("href" in props) {
return (
<IconBlockLink
ref={ref as React.ForwardedRef<HTMLAnchorElement>}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
$color={$color}
{...props}
/>
Expand Down
3 changes: 0 additions & 3 deletions src/components/header/accountDrawer/TestnetsToggle.tsx

This file was deleted.

16 changes: 5 additions & 11 deletions src/components/header/selector/ChainSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ConfigId, ProtocolConfig } from "@bosonprotocol/react-kit";
import { ChainId } from "@uniswap/sdk-core";
import { useWeb3React } from "@web3-react/core";
import { useConfigContext } from "components/config/ConfigContext";
import { useAtomValue } from "jotai";
import { envConfigsFilteredByEnv } from "lib/config";
import {
CaretDown as ChevronDown,
Expand All @@ -28,7 +27,6 @@ import useSelectChain from "../../../lib/utils/hooks/useSelectChain";
import useSyncChainQuery from "../../../lib/utils/hooks/useSyncChainQuery";
import { Portal } from "../../portal/Portal";
import Tooltip from "../../tooltip/Tooltip";
import { showTestnetsAtom } from "../accountDrawer/TestnetsToggle";
import { NavDropdown } from "../navDropdown/NavDropdown";
import ChainSelectorRow from "./ChainSelectorRow";

Expand Down Expand Up @@ -75,20 +73,21 @@ function useWalletSupportedChains(): ChainId[] {
return NETWORK_SELECTOR_CHAINS_IDS;
}
}

const chevronProps = {
height: 20,
width: 20
};
export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
const { config } = useConfigContext();
const [isOpen, setIsOpen] = useState<boolean>(false);
const { isXS: isMobile } = useBreakpoints();

const showTestnets = useAtomValue(showTestnetsAtom);
const walletSupportsChain = useWalletSupportedChains();

const [supportedConfigs, unsupportedChains] = useMemo(() => {
const { supported, unsupported } = NETWORK_SELECTOR_CHAINS.filter(
(config) => {
return (
showTestnets ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
!TESTNET_CHAIN_IDS.includes(config.chainId as any)
);
Expand All @@ -111,7 +110,7 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
{ supported: [], unsupported: [] } as Record<string, ProtocolConfig[]>
);
return [supported, unsupported];
}, [showTestnets, walletSupportsChain]);
}, [walletSupportsChain]);

const ref = useRef<HTMLDivElement>(null);
const modalRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -177,11 +176,6 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
</NavDropdown>
);

const chevronProps = {
height: 20,
width: 20
};

return (
<div style={{ position: "relative", display: "flex" }} ref={ref}>
<Tooltip
Expand Down
31 changes: 30 additions & 1 deletion src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import "styled-components";

import { theme as bosonTheme } from "@bosonprotocol/react-kit";
import {
BaseTagsInputProps,
theme as bosonTheme
} from "@bosonprotocol/react-kit";
import { colors } from "lib/styles/colors";

const theme = {
...bosonTheme
};

export const inputTheme = {
background: colors.lightGrey,
borderColor: colors.border,
borderRadius: 0,
focus: {
caretColor: "initial"
},
hover: {
borderColor: "var(--secondary)"
},
error: {
borderColor: colors.orange,
hover: {
borderColor: colors.orange
},
focus: {
borderColor: "var(--secondary)",
caretColor: colors.orange
},
placeholder: {
color: colors.orange
}
}
} satisfies BaseTagsInputProps["theme"];

export default theme;

0 comments on commit d2ed435

Please sign in to comment.