InputField with suffix select (#5683)

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
sean-brydon
2022-11-28 11:20:49 +00:00
committed by GitHub
co-authored by Peer Richelsen
parent 798a4b0090
commit ae9f66c9ef
6 changed files with 93 additions and 15 deletions
+1
View File
@@ -13,5 +13,6 @@ export {
TextArea,
TextAreaField,
TextField,
InputFieldWithSelect,
} from "./inputs/Input";
export { Label } from "./inputs/Label";
+43 -13
View File
@@ -6,19 +6,23 @@ import classNames from "@calcom/lib/classNames";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert, showToast, Skeleton, Tooltip } from "../../..";
import { Alert, showToast, Skeleton, Tooltip, UnstyledSelect } from "../../..";
import { HintsOrErrors } from "./HintOrErrors";
import { Label } from "./Label";
type InputProps = JSX.IntrinsicElements["input"];
type InputProps = JSX.IntrinsicElements["input"] & { isFullWidth?: boolean };
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(props, ref) {
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
{ isFullWidth = true, ...props },
ref
) {
return (
<input
{...props}
ref={ref}
className={classNames(
"mb-2 block h-9 w-full rounded-md border border-gray-300 py-2 px-3 text-sm placeholder:text-gray-400 hover:border-gray-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-neutral-800 focus:ring-offset-1",
"mb-2 block h-9 rounded-md border border-gray-300 py-2 px-3 text-sm placeholder:text-gray-400 hover:border-gray-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-neutral-800 focus:ring-offset-1",
isFullWidth && "w-full",
props.className
)}
/>
@@ -39,6 +43,9 @@ type InputFieldProps = {
hintErrors?: string[];
addOnLeading?: ReactNode;
addOnSuffix?: ReactNode;
inputIsFullWidth?: boolean;
/**@Default paddingX 12px */
addOnPadding?: number;
addOnFilled?: boolean;
error?: string;
labelSrOnly?: boolean;
@@ -54,15 +61,13 @@ type AddonProps = {
isFilled?: boolean;
className?: string;
error?: boolean;
paddingX?: number;
};
const Addon = ({ isFilled, children, className, error }: AddonProps) => (
const Addon = ({ isFilled, children, className, error, paddingX = 12 }: AddonProps) => (
<div
className={classNames(
"addon-wrapper h-9 border border-gray-300 px-3",
isFilled && "bg-gray-100",
className
)}>
style={{ padding: `0 ${paddingX}px` }}
className={classNames("addon-wrapper h-9 border border-gray-300", isFilled && "bg-gray-100", className)}>
<div className={classNames("flex h-full flex-col justify-center text-sm", error && "text-red-900")}>
<span className="whitespace-nowrap py-2.5">{children}</span>
</div>
@@ -83,6 +88,8 @@ export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function
addOnLeading,
addOnSuffix,
addOnFilled = true,
addOnPadding,
inputIsFullWidth,
hint,
hintErrors,
labelSrOnly,
@@ -107,13 +114,14 @@ export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function
{addOnLeading || addOnSuffix ? (
<div className="relative mb-1 flex items-center rounded-md focus-within:outline-none focus-within:ring-2 focus-within:ring-neutral-800 focus-within:ring-offset-1">
{addOnLeading && (
<Addon isFilled={addOnFilled} className="rounded-l-md border-r-0">
<Addon isFilled={addOnFilled} className="rounded-l-md border-r-0" paddingX={addOnPadding}>
{addOnLeading}
</Addon>
)}
<Input
id={id}
placeholder={placeholder}
isFullWidth={inputIsFullWidth}
className={classNames(
className,
addOnLeading && "rounded-l-none",
@@ -124,13 +132,20 @@ export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function
ref={ref}
/>
{addOnSuffix && (
<Addon isFilled={addOnFilled} className="rounded-r-md border-l-0">
<Addon isFilled={addOnFilled} className="rounded-r-md border-l-0" paddingX={addOnPadding}>
{addOnSuffix}
</Addon>
)}
</div>
) : (
<Input id={id} placeholder={placeholder} className={className} {...passThrough} ref={ref} />
<Input
id={id}
placeholder={placeholder}
className={className}
{...passThrough}
ref={ref}
isFullWidth={inputIsFullWidth}
/>
)}
<HintsOrErrors hintErrors={hintErrors} fieldName={name} t={t} />
{hint && <div className="text-gray mt-2 flex items-center text-sm text-gray-700">{hint}</div>}
@@ -319,3 +334,18 @@ export function InputGroupBox(props: JSX.IntrinsicElements["div"]) {
</div>
);
}
export const InputFieldWithSelect = forwardRef<
HTMLInputElement,
InputFieldProps & { selectProps: typeof UnstyledSelect }
>(function EmailField(props, ref) {
return (
<InputField
ref={ref}
{...props}
inputIsFullWidth={false}
addOnPadding={0}
addOnSuffix={<UnstyledSelect {...props.selectProps} />}
/>
);
});
@@ -1,6 +1,6 @@
import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
import { Examples, Example, Note, Title,CustomArgsTable, VariantRow,VariantsTable} from '@calcom/storybook/components'
import { Icon } from "@calcom/ui";
import { Icon,Select,UnstyledSelect,InputFieldWithSelect } from "@calcom/ui";
import {InputField} from "./Input"
@@ -35,6 +35,9 @@ Text fields allow users to input and edit text into the product. Usually appear
<Example title="Suffix">
<InputField placeholder="Suffic" addOnSuffix={<>Suffix</>}/>
</Example>
<Example title="Suffix With Select">
<InputFieldWithSelect placeholder="Suffix" selectProps={{options:[{value:"TEXT",label:"Text"}]}}/>
</Example>
<Example title="Focused">
<InputField placeholder="Focused" className="sb-pseudo--focus"/>
</Example>
+1
View File
@@ -22,6 +22,7 @@ export {
TextArea,
TextAreaField,
TextField,
InputFieldWithSelect,
} from "./form";
export { TopBanner } from "./top-banner";
export type { TopBannerProps } from "./top-banner";
+42
View File
@@ -61,3 +61,45 @@ function Select<
}
export default Select;
export function UnstyledSelect<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>
>({ className, ...props }: SelectProps<Option, IsMulti, Group>) {
return (
<ReactSelect
{...props}
isSearchable={false}
theme={(theme) => ({ ...theme, borderRadius: 0, border: "none" })}
components={{
IndicatorSeparator: () => null,
Input: InputComponent,
}}
styles={{
container: (provided) => ({
...provided,
width: "100%",
}),
control: (provided) => ({
...provided,
backgroundColor: " transparent",
border: "none",
boxShadow: "none",
}),
option: (provided, state) => ({
...provided,
color: state.isSelected ? "var(--brand-text-color)" : "black",
":active": {
backgroundColor: state.isSelected ? "" : "var(--brand-color)",
color: "var(--brand-text-color)",
},
}),
indicatorSeparator: () => ({
display: "hidden",
color: "black",
}),
}}
/>
);
}
+2 -1
View File
@@ -16,6 +16,7 @@ export {
Input,
InputField,
InputGroupBox,
InputFieldWithSelect,
InputLeading,
Label,
PasswordField,
@@ -30,7 +31,7 @@ export { default as CheckboxField } from "./components/form/checkbox/Checkbox";
export { default as ErrorBoundary } from "./ErrorBoundary";
export { default as AddressInput } from "./form/AddressInputLazy";
export { default as PhoneInput } from "./form/PhoneInputLazy";
export { default as Select } from "./form/Select";
export { default as Select, UnstyledSelect } from "./form/Select";
export { BadgeCheckIcon, ClipboardCopyIcon, Icon, ShieldCheckIcon, StarIconSolid } from "./Icon";
export { default as Loader } from "./Loader";
export { default as Shell, ShellMain } from "./Shell";