Skip to content

Commit

Permalink
refactor: split InputOrGroup into smaller files
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Oct 17, 2023
1 parent a7d9a28 commit 250d7d5
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 237 deletions.
90 changes: 90 additions & 0 deletions packages/core/components/InputOrGroup/fields/ArrayField/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import { List, Trash } from "react-feather";
import { InputOrGroup, type InputProps } from "../..";
import { IconButton } from "../../../IconButton";
import { replace } from "../../../../lib";

const getClassName = getClassNameFactory("Input", styles);

export const ArrayField = ({
field,
onChange,
value,
name,
label,
}: InputProps) => {
if (!field.arrayFields) {
return null;
}

return (
<div className={getClassName()}>
<b className={getClassName("label")}>
<div className={getClassName("labelIcon")}>
<List size={16} />
</div>
{label || name}
</b>
<div className={getClassName("array")}>
{Array.isArray(value) ? (
value.map((item, i) => (
<details key={`${name}_${i}`} className={getClassName("arrayItem")}>
<summary>
{field.getItemSummary
? field.getItemSummary(item, i)
: `Item #${i}`}

<div className={getClassName("arrayItemAction")}>
<IconButton
onClick={() => {
const existingValue = value || [];

existingValue.splice(i, 1);
onChange(existingValue);
}}
title="Delete"
>
<Trash size={21} />
</IconButton>
</div>
</summary>
<fieldset className={getClassName("fieldset")}>
{Object.keys(field.arrayFields!).map((fieldName) => {
const subField = field.arrayFields![fieldName];

return (
<InputOrGroup
key={`${name}_${i}_${fieldName}`}
name={`${name}_${i}_${fieldName}`}
label={subField.label || fieldName}
field={subField}
value={item[fieldName]}
onChange={(val) =>
onChange(
replace(value, i, { ...item, [fieldName]: val })
)
}
/>
);
})}
</fieldset>
</details>
))
) : (
<div />
)}

<button
className={getClassName("addButton")}
onClick={() => {
const existingValue = value || [];
onChange([...existingValue, field.defaultItemProps || {}]);
}}
>
+ Add item
</button>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import { Hash, Type } from "react-feather";
import type { InputProps } from "../..";

const getClassName = getClassNameFactory("Input", styles);

export const DefaultField = ({
field,
onChange,
readOnly,
value,
name,
label,
}: InputProps) => {
return (
<label className={getClassName({ readOnly })}>
<div className={getClassName("label")}>
<div className={getClassName("labelIcon")}>
{field.type === "text" && <Type size={16} />}
{field.type === "number" && <Hash size={16} />}
</div>
{label || name}
</div>
<input
className={getClassName("input")}
autoComplete="off"
type={field.type}
name={name}
value={typeof value === "undefined" ? "" : value}
onChange={(e) => {
if (field.type === "number") {
onChange(Number(e.currentTarget.value));
} else {
onChange(e.currentTarget.value);
}
}}
readOnly={readOnly}
/>
</label>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import type { InputProps } from "../..";
import { ExternalInput } from "../../../ExternalInput";

const getClassName = getClassNameFactory("Input", styles);

export const ExternalField = ({
field,
onChange,
readOnly,
value,
name,
label,
}: InputProps) => {
if (!field.adaptor) {
return null;
}

return (
<div className={getClassName("")}>
<div className={getClassName("label")}>
{name === "_data" ? "External content" : label || name}
</div>
<ExternalInput field={field} onChange={onChange} value={value} />
</div>
);
};
63 changes: 63 additions & 0 deletions packages/core/components/InputOrGroup/fields/RadioField/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import { CheckCircle } from "react-feather";
import type { InputProps } from "../..";

const getClassName = getClassNameFactory("Input", styles);

export const RadioField = ({
field,
onChange,
readOnly,
value,
name,
}: InputProps) => {
if (!field.options) {
return null;
}

return (
<div className={getClassName()}>
<div className={getClassName("radioGroup")}>
<div className={getClassName("label")}>
<div className={getClassName("labelIcon")}>
<CheckCircle size={16} />
</div>
{field.label || name}
</div>

<div className={getClassName("radioGroupItems")}>
{field.options.map((option) => (
<label
key={option.label + option.value}
className={getClassName("radio")}
>
<input
type="radio"
className={getClassName("radioInput")}
value={option.value as string | number}
name={name}
onChange={(e) => {
if (
e.currentTarget.value === "true" ||
e.currentTarget.value === "false"
) {
onChange(JSON.parse(e.currentTarget.value));
return;
}

onChange(e.currentTarget.value);
}}
readOnly={readOnly}
defaultChecked={value === option.value}
/>
<div className={getClassName("radioInner")}>
{option.label || option.value}
</div>
</label>
))}
</div>
</div>
</div>
);
};
52 changes: 52 additions & 0 deletions packages/core/components/InputOrGroup/fields/SelectField/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import { ChevronDown } from "react-feather";
import type { InputProps } from "../..";

const getClassName = getClassNameFactory("Input", styles);

export const SelectField = ({
field,
onChange,
label,
value,
name,
}: InputProps) => {
if (!field.options) {
return null;
}

return (
<label className={getClassName()}>
<div className={getClassName("label")}>
<div className={getClassName("labelIcon")}>
<ChevronDown size={16} />
</div>
{label || name}
</div>
<select
className={getClassName("input")}
onChange={(e) => {
if (
e.currentTarget.value === "true" ||
e.currentTarget.value === "false"
) {
onChange(Boolean(e.currentTarget.value));
return;
}

onChange(e.currentTarget.value);
}}
value={value}
>
{field.options.map((option) => (
<option
key={option.label + option.value}
label={option.label}
value={option.value as string | number}
/>
))}
</select>
</label>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import getClassNameFactory from "../../../../lib/get-class-name-factory";
import styles from "../../styles.module.css";
import { Type } from "react-feather";
import type { InputProps } from "../..";

const getClassName = getClassNameFactory("Input", styles);

export const TextareaField = ({
onChange,
readOnly,
value,
name,
label,
}: InputProps) => {
return (
<label className={getClassName({ readOnly })}>
<div className={getClassName("label")}>
<div className={getClassName("labelIcon")}>
<Type size={16} />
</div>
{label || name}
</div>
<textarea
className={getClassName("input")}
autoComplete="off"
name={name}
value={typeof value === "undefined" ? "" : value}
onChange={(e) => onChange(e.currentTarget.value)}
readOnly={readOnly}
rows={5}
/>
</label>
);
};
6 changes: 6 additions & 0 deletions packages/core/components/InputOrGroup/fields/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from "./ArrayField";
export * from "./DefaultField";
export * from "./ExternalField";
export * from "./RadioField";
export * from "./SelectField";
export * from "./TextareaField";
Loading

0 comments on commit 250d7d5

Please sign in to comment.