ActionList.jsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import React from "react";
  2. import { FieldArray } from "react-final-form-arrays";
  3. import { useField } from "react-final-form";
  4. import { useTranslation } from "react-i18next";
  5. import styled from "styled-components";
  6. import { smallUid } from "../utils";
  7. import useGameItemActions from "./useGameItemActions";
  8. const StyledActionList = styled.div`
  9. & .action-list {
  10. list-style: none;
  11. margin: 0;
  12. padding: 0 0 1em 0;
  13. }
  14. & .action-list li {
  15. display: flex;
  16. flex-direction: column;
  17. margin: 0.2em 0;
  18. padding: 0.2em 0;
  19. border-bottom: 1px solid #242d3e;
  20. & button {
  21. padding: 0.2em;
  22. }
  23. & .action-desc {
  24. display: flex;
  25. justify-content: space-between;
  26. }
  27. & .action-form {
  28. margin: 0.3em 0 0.2em 1em;
  29. padding: 0.5em;
  30. background-color: var(--bg-secondary-color);
  31. }
  32. }
  33. `;
  34. const Action = ({ name, onUp, onDown, onRemove }) => {
  35. const { t } = useTranslation();
  36. const {
  37. input: { value },
  38. } = useField(name);
  39. const [showForm, setShowForm] = React.useState(false);
  40. const { actionMap } = useGameItemActions();
  41. const { form: ActionForm, label } = actionMap[value.name];
  42. const hasForm = Boolean(ActionForm);
  43. return (
  44. <li>
  45. <div className="action-desc">
  46. <span>{label(value.args)}</span>
  47. <div className="action-actions">
  48. {hasForm && (
  49. <button
  50. onClick={() => setShowForm((prev) => !prev)}
  51. className={showForm ? "button primary" : ""}
  52. >
  53. <img
  54. src="https://icongr.am/feather/edit.svg?size=20&color=FFFFFF"
  55. alt={t("Edit action")}
  56. title={t("Edit action")}
  57. />
  58. </button>
  59. )}
  60. <button onClick={onUp} disabled={!onUp}>
  61. <img
  62. src="https://icongr.am/feather/arrow-up.svg?size=20&color=FFFFFF"
  63. alt={t("Move up")}
  64. title={t("Move up")}
  65. />
  66. </button>
  67. <button onClick={onDown} disabled={!onDown}>
  68. <img
  69. src="https://icongr.am/feather/arrow-down.svg?size=20&color=FFFFFF"
  70. alt={t("Move down")}
  71. title={t("Move down")}
  72. />
  73. </button>
  74. <button onClick={onRemove}>
  75. <img
  76. src="https://icongr.am/feather/x.svg?size=20&color=FFFFFF"
  77. alt={t("Remove")}
  78. title={t("Remove")}
  79. />
  80. </button>
  81. </div>
  82. </div>
  83. {hasForm && showForm && (
  84. <div className="action-form">
  85. <ActionForm name={`${name}.args`} initialValues={value.args} />
  86. </div>
  87. )}
  88. </li>
  89. );
  90. };
  91. const ActionList = ({ name, initialValue, availableActions = [] }) => {
  92. const { t } = useTranslation();
  93. const { actionMap } = useGameItemActions();
  94. const onAdd = (fields) => (e) => {
  95. const name = e.target.value;
  96. if (name) {
  97. fields.push({ name, uid: smallUid() });
  98. }
  99. e.target.value = "";
  100. };
  101. return (
  102. <FieldArray name={name} initialValue={initialValue}>
  103. {({ fields }) => (
  104. <StyledActionList>
  105. <ul className="action-list">
  106. {fields.map((name, index, uid) => (
  107. <Action
  108. key={`${name}-${uid}`}
  109. name={name}
  110. onRemove={() => fields.remove(index)}
  111. onUp={index > 0 ? () => fields.swap(index, index - 1) : null}
  112. onDown={
  113. index < fields.length - 1
  114. ? () => fields.swap(index, index + 1)
  115. : null
  116. }
  117. />
  118. ))}
  119. </ul>
  120. <select onChange={onAdd(fields)}>
  121. <option key={name} value={""}>
  122. {t("Select an action to add...")}
  123. </option>
  124. {availableActions.map((name) => {
  125. return (
  126. <option key={name} value={name}>
  127. {actionMap[name].genericLabel || actionMap[name].label()}
  128. </option>
  129. );
  130. })}
  131. </select>
  132. </StyledActionList>
  133. )}
  134. </FieldArray>
  135. );
  136. };
  137. export default ActionList;