123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- import React from "react";
- import { useTranslation } from "react-i18next";
- import { Field } from "react-final-form";
- import Label from "../ui/formUtils/Label";
- import Hint from "../ui/formUtils/Hint";
- import Slider from "../ui/Slider";
- import ActionList from "./ActionList";
- import { itemTemplates } from "./";
- export const getFormFieldComponent = (type) => {
- if (type in itemTemplates) {
- return itemTemplates[type].form;
- }
- return () => null;
- };
- const getDefaultActionsFromItem = (item) => {
- if (item.type in itemTemplates) {
- const actions = itemTemplates[item.type].defaultActions;
- if (typeof actions === "function") {
- return actions(item);
- }
- return actions;
- }
- return [];
- };
- const getAvailableActionsFromItem = (item) => {
- if (item.type in itemTemplates) {
- const actions = itemTemplates[item.type].availableActions;
- if (typeof actions === "function") {
- return actions(item);
- }
- return actions;
- }
- return [];
- };
- const getExcludedFields = (types) => {
- return types.reduce((excluded, type) => {
- return Object.assign(excluded, itemTemplates[type].excludeFields || {});
- }, {});
- };
- const ItemForm = ({ items, types, extraExcludeFields = {} }) => {
- const { t } = useTranslation();
- let FieldsComponent;
- const oneType = types.length === 1;
- if (items.length === 1) {
- FieldsComponent = getFormFieldComponent(items[0].type);
- } else {
- if (oneType) {
- FieldsComponent = getFormFieldComponent(types[0]);
- } else {
- FieldsComponent = () => null;
- }
- }
- const defaultActions = React.useMemo(() => {
- if (oneType) {
- return getDefaultActionsFromItem(items[0]);
- }
- return undefined;
- }, [items, oneType]);
- const availableActions = React.useMemo(() => {
- if (oneType) {
- return getAvailableActionsFromItem(items[0]);
- }
- return [];
- }, [items, oneType]);
- // Merge extra excluded fields and all item excluded fields
- const excludeFields = { ...getExcludedFields(types), ...extraExcludeFields };
- let initialValues;
- // Set initial values to item values only if one element selected
- // Empty object otherwise
- if (items.length === 1) {
- initialValues = { ...items[0] };
- if (items.length === 1) {
- initialValues.actions = (initialValues.actions || defaultActions).map(
- (action) => {
- if (typeof action === "string") {
- return { name: action };
- }
- return action;
- }
- );
- }
- } else {
- initialValues = {};
- }
- return (
- <>
- {!excludeFields.locked && (
- <Label>
- <Field
- name="locked"
- component="input"
- type="checkbox"
- initialValue={initialValues.locked}
- />
- <span className="checkable">{t("Locked?")}</span>
- <Hint>{t("Lock action help")}</Hint>
- </Label>
- )}
- {!excludeFields.rotation && (
- <Label>
- {t("Rotation")}
- <Field name="rotation" initialValue={initialValues.rotation}>
- {({ input: { onChange, value } }) => {
- return (
- <Slider
- defaultValue={0}
- value={value}
- min={-180}
- max={180}
- step={5}
- included={false}
- marks={{
- "-180": -180,
- "-90": -90,
- "-45": -45,
- "-30": -30,
- 0: 0,
- 30: 30,
- 45: 45,
- 90: 90,
- 180: 180,
- }}
- onChange={onChange}
- className={"slider-rotation"}
- />
- );
- }}
- </Field>
- </Label>
- )}
- {!excludeFields.layer && (
- <Label>
- {t("Layer")}
- <Field name="layer" initialValue={initialValues.layer}>
- {({ input: { onChange, value } }) => {
- return (
- <Slider
- defaultValue={0}
- value={value}
- min={-3}
- max={3}
- step={1}
- included={false}
- marks={{
- "-3": -3,
- "-2": -2,
- "-1": -1,
- 0: 0,
- "1": 1,
- "2": 2,
- "3": 3,
- }}
- onChange={onChange}
- className={"slider-layer"}
- />
- );
- }}
- </Field>
- </Label>
- )}
- <FieldsComponent initialValues={initialValues} />
- <h3>{t("Snap to grid")}</h3>
- <Label>
- {t("Grid type")}
- <Field
- name="grid.type"
- initialValue={initialValues.grid?.type}
- component="select"
- >
- <option value="none">{t("None")}</option>
- <option value="grid">{t("Grid")}</option>
- <option value="hexH">{t("Horizontal hexagons")}</option>
- <option value="hexV">{t("Vertical hexagons")}</option>
- </Field>
- </Label>
- <Label>
- {t("Size")}
- <Field
- name="grid.size"
- component="input"
- initialValue={initialValues.grid?.size}
- >
- {(props) => <input {...props.input} type="number" />}
- </Field>
- </Label>
- {oneType && (
- <>
- <h3>{t("Item actions")}</h3>
- <ActionList
- name="actions"
- initialValue={initialValues.actions}
- availableActions={availableActions}
- />
- </>
- )}
- </>
- );
- };
- export default React.memo(ItemForm);
|