strapi-plugin-hubspot 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +18 -0
  3. package/dist/_chunks/{Forms-DadTbe9Q.mjs → Forms-CHB-sKem.mjs} +218 -121
  4. package/dist/_chunks/{Forms-Dn2W6OS4.js → Forms-lrzuWzoB.js} +217 -120
  5. package/dist/_chunks/{HubspotFormInput-S_Z2t_DN.js → HubspotFormInput-Bb6it0nP.js} +1 -1
  6. package/dist/_chunks/{HubspotFormInput-NO59AtM_.mjs → HubspotFormInput-YI09keTC.mjs} +1 -1
  7. package/dist/_chunks/{HubspotObjectInput-DAo3FAMz.mjs → HubspotObjectInput-CzLKT9oj.mjs} +3 -3
  8. package/dist/_chunks/{HubspotObjectInput-BIgIa_Dm.js → HubspotObjectInput-D3A6xzb3.js} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-KX1Bhcsl.mjs → HubspotPropertyInput-DicskLcN.mjs} +3 -3
  10. package/dist/_chunks/{HubspotPropertyInput-B-piLcIy.js → HubspotPropertyInput-Dss3eUlL.js} +3 -3
  11. package/dist/_chunks/{Settings-Dz0PEFOv.mjs → Settings-4CbX3SPK.mjs} +2 -2
  12. package/dist/_chunks/{Settings-DMu_QThB.js → Settings-Ch8tPZAV.js} +2 -2
  13. package/dist/_chunks/{en-CH5LSPkL.mjs → en-D8DJiSxd.mjs} +3 -1
  14. package/dist/_chunks/{en-BDGqW_yS.js → en-PYFibnDc.js} +3 -1
  15. package/dist/_chunks/{fr-65-RaB3w.mjs → fr-BMjixfXn.mjs} +3 -1
  16. package/dist/_chunks/{fr-C82LMqUM.js → fr-yHk4sSEl.js} +3 -1
  17. package/dist/_chunks/{index-B7Ru1fu5.js → index-BAvedd2m.js} +6 -6
  18. package/dist/_chunks/{index-DA31TY2n.mjs → index-BE2ribUL.mjs} +6 -6
  19. package/dist/_chunks/{objectLabels-FTh984_h.js → objectLabels-CycoU0zY.js} +1 -1
  20. package/dist/_chunks/{objectLabels-Bl7sO5pb.mjs → objectLabels-DGJxYjKz.mjs} +1 -1
  21. package/dist/_chunks/{useHubspotSchema-C2_PuXEm.js → useHubspotSchema-DRfaI6mF.js} +1 -1
  22. package/dist/_chunks/{useHubspotSchema-BlDilCHc.mjs → useHubspotSchema-e31UsYb2.mjs} +1 -1
  23. package/dist/admin/index.js +1 -1
  24. package/dist/admin/index.mjs +1 -1
  25. package/dist/admin/src/builder/Sortable.d.ts +25 -0
  26. package/dist/admin/src/builder/__tests__/CompanyMapEditor.test.d.ts +1 -0
  27. package/dist/admin/src/builder/__tests__/ConditionEditor.test.d.ts +1 -0
  28. package/dist/admin/src/builder/__tests__/testUtils.d.ts +4 -0
  29. package/dist/server/index.js +101 -42
  30. package/dist/server/index.mjs +101 -42
  31. package/dist/server/src/__tests__/contract.test.d.ts +1 -0
  32. package/dist/server/src/__tests__/rateLimit.test.d.ts +1 -0
  33. package/dist/server/src/index.d.ts +12 -3
  34. package/dist/server/src/rateLimit.d.ts +18 -0
  35. package/package.json +11 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.0 — 2026-08-31
4
+
5
+ ### Added
6
+ - **Drag & drop in the builder** (@dnd-kit): steps reorder among themselves,
7
+ fields reorder within their step — grab the grip handle; an 8px activation
8
+ distance keeps plain clicks selecting as before. The arrow buttons stay:
9
+ they remain the accessible path and the way to slide a field into the
10
+ neighbouring step.
11
+
12
+ ### Also in this release — anti-spam & frozen contract
13
+ - **Per-IP rate limiting** on the public routes (sliding window, in-memory):
14
+ submissions 6/min, company searches 30/min — `forms.rateLimit`
15
+ config, `0` disables one. Over the limit → `429`.
16
+ - **Honeypot**: a submission whose hidden `__hp` key is filled gets a normal
17
+ success and is neither sent nor stored — no signal for the bot to adapt to.
18
+ (Frontends: render a visually hidden `__hp` input.)
19
+ - **Contract test suite** freezing the 1.0 public surface: public form
20
+ payload keys, CRM mappings never leaked, submission conventions
21
+ (`__siret`/`__company`/`__hp`, structured `missingRequired`), the 12
22
+ condition operators. A failure there means "bump the major".
23
+ - README: *Stability & versioning* section documenting the frozen contract
24
+ and the `version: 2` migration promise.
25
+
3
26
  ## 0.11.1 — 2026-08-29
4
27
 
5
28
  Ships the company-search sharpening that missed the 0.11.0 tarball (the
package/README.md CHANGED
@@ -342,6 +342,24 @@ authenticated admin, since the picker needs it in the Content Manager.
342
342
  > reaches the browser, but treat it like any other secret in your database. Use
343
343
  > `HUBSPOT_API_KEY` if your deployment already manages secrets properly.
344
344
 
345
+ ## Stability & versioning
346
+
347
+ From 1.0 onward this plugin follows semver against a **frozen public
348
+ contract**, enforced by a dedicated test suite (`contract.test.ts`):
349
+
350
+ - the **definition document** (`version: 1`): steps → fields → `visibleIf`
351
+ conditions, the 12 operators, stable `stp_`/`fld_` ids;
352
+ - the **public API payloads**: `GET /forms/:slug` (rendering props served,
353
+ CRM mappings never), `POST /forms/:slug/submit` and its structured 422,
354
+ `GET /company-search`;
355
+ - the **submission conventions**: values keyed by field `name`, company
356
+ companion keys `<name>__siret` / `<name>__company`, honeypot `__hp`;
357
+ - the exported types (`strapi-plugin-hubspot/types`).
358
+
359
+ Anything else — admin UI, internals, HubSpot plumbing — may improve in minor
360
+ versions. Breaking any of the above means a major version, and a `version: 2`
361
+ definition would ship with an automatic migration from `version: 1`.
362
+
345
363
  ## Install
346
364
 
347
365
  ```bash
@@ -3,11 +3,14 @@ import { useParams, useSearchParams, Link, useNavigate, Routes, Route } from "re
3
3
  import * as React from "react";
4
4
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
5
5
  import { Typography, Flex, Box, SingleSelect, SingleSelectOption, MultiSelect, MultiSelectOption, TextInput, IconButton, Button, Combobox, ComboboxOption, Field, Textarea, Checkbox, Divider, Loader, Badge, Table, Thead, Tr, Th, Tbody, Td, Modal } from "@strapi/design-system";
6
- import { Trash, Plus, ArrowClockwise, ArrowLeft, ArrowUp, ArrowDown, List, Duplicate, Download } from "@strapi/icons";
6
+ import { Trash, Plus, ArrowClockwise, ArrowLeft, Drag, ArrowUp, ArrowDown, List, Duplicate, Download } from "@strapi/icons";
7
7
  import { useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTranslation, P as PLUGIN_ID } from "./index-DA31TY2n.mjs";
9
- import { o as objectLabel } from "./objectLabels-Bl7sO5pb.mjs";
10
- import { u as useHubspotSchema } from "./useHubspotSchema-BlDilCHc.mjs";
8
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-BE2ribUL.mjs";
9
+ import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from "@dnd-kit/core";
10
+ import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from "@dnd-kit/sortable";
11
+ import { CSS } from "@dnd-kit/utilities";
12
+ import { o as objectLabel } from "./objectLabels-DGJxYjKz.mjs";
13
+ import { u as useHubspotSchema } from "./useHubspotSchema-e31UsYb2.mjs";
11
14
  const OPERATORS = [
12
15
  "eq",
13
16
  "neq",
@@ -150,6 +153,48 @@ const ConditionEditor = ({ condition, candidates, onChange }) => {
150
153
  ] })
151
154
  ] });
152
155
  };
156
+ function SortableList({
157
+ ids,
158
+ onReorder,
159
+ children
160
+ }) {
161
+ const sensors = useSensors(
162
+ // An 8px activation distance keeps clicks (selection!) from starting drags.
163
+ useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
164
+ useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
165
+ );
166
+ const handleDragEnd = (event) => {
167
+ const { active, over } = event;
168
+ if (!over || active.id === over.id) return;
169
+ const from = ids.indexOf(String(active.id));
170
+ const to = ids.indexOf(String(over.id));
171
+ if (from === -1 || to === -1) return;
172
+ onReorder(arrayMove(ids, from, to));
173
+ };
174
+ return /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(SortableContext, { items: ids, strategy: verticalListSortingStrategy, children }) });
175
+ }
176
+ function SortableItem({
177
+ id,
178
+ children
179
+ }) {
180
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
181
+ id
182
+ });
183
+ return /* @__PURE__ */ jsx(
184
+ "div",
185
+ {
186
+ ref: setNodeRef,
187
+ style: {
188
+ transform: CSS.Transform.toString(transform),
189
+ transition,
190
+ opacity: isDragging ? 0.5 : void 0,
191
+ zIndex: isDragging ? 2 : void 0,
192
+ position: "relative"
193
+ },
194
+ children: children({ attributes, listeners })
195
+ }
196
+ );
197
+ }
153
198
  const FIELD_TYPES = [
154
199
  "text",
155
200
  "email",
@@ -672,6 +717,10 @@ const FormEditor = () => {
672
717
  }
673
718
  return next;
674
719
  });
720
+ function reorderByIds(items, ids) {
721
+ const byId = new Map(items.map((item) => [item.id, item]));
722
+ return ids.map((id) => byId.get(id)).filter((item) => Boolean(item));
723
+ }
675
724
  const moveStep = (stepIndex, delta) => patchDefinition((steps) => {
676
725
  const target = stepIndex + delta;
677
726
  if (target < 0 || target >= steps.length) return steps;
@@ -793,154 +842,202 @@ const FormEditor = () => {
793
842
  feedback && /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(Typography, { textColor: feedback.tone === "success" ? "success600" : "danger600", children: feedback.text }) }),
794
843
  /* @__PURE__ */ jsxs(Flex, { gap: 6, alignItems: "flex-start", children: [
795
844
  /* @__PURE__ */ jsx(Box, { flex: "1", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
796
- definition.steps.map((step, stepIndex) => /* @__PURE__ */ jsxs(
797
- Box,
845
+ /* @__PURE__ */ jsx(
846
+ SortableList,
798
847
  {
799
- background: "neutral0",
800
- hasRadius: true,
801
- shadow: "tableShadow",
802
- padding: 4,
803
- onClick: () => setSelection({ kind: "step", stepId: step.id }),
804
- style: { cursor: "pointer" },
805
- borderColor: selection.kind === "step" && selection.stepId === step.id ? "primary600" : void 0,
806
- borderStyle: selection.kind === "step" && selection.stepId === step.id ? "solid" : void 0,
807
- borderWidth: selection.kind === "step" && selection.stepId === step.id ? "1px" : void 0,
808
- children: [
809
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", paddingBottom: 2, children: [
810
- /* @__PURE__ */ jsxs(
811
- Flex,
848
+ ids: definition.steps.map((s) => s.id),
849
+ onReorder: (ids) => patchDefinition((steps) => reorderByIds(steps, ids)),
850
+ children: definition.steps.map((step, stepIndex) => /* @__PURE__ */ jsx(
851
+ SortableItem,
852
+ {
853
+ id: step.id,
854
+ children: (stepHandle) => /* @__PURE__ */ jsxs(
855
+ Box,
812
856
  {
813
- gap: 2,
814
- alignItems: "center",
857
+ background: "neutral0",
858
+ hasRadius: true,
859
+ shadow: "tableShadow",
860
+ padding: 4,
815
861
  onClick: () => setSelection({ kind: "step", stepId: step.id }),
816
862
  style: { cursor: "pointer" },
863
+ borderColor: selection.kind === "step" && selection.stepId === step.id ? "primary600" : void 0,
864
+ borderStyle: selection.kind === "step" && selection.stepId === step.id ? "solid" : void 0,
865
+ borderWidth: selection.kind === "step" && selection.stepId === step.id ? "1px" : void 0,
817
866
  children: [
818
- /* @__PURE__ */ jsxs(Typography, { variant: "delta", children: [
819
- t("editor.step", "Step {n}", { n: stepIndex + 1 }),
820
- step.title ? ` — ${step.title}` : ""
821
- ] }),
822
- step.visibleIf?.rules?.length ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "alternative100", textColor: "alternative700", children: t("editor.conditional", "Conditional") }) : null,
823
- errors.some((e) => e.stepId === step.id) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "danger100", textColor: "danger700", children: t("editor.flag-error", "To fix") })
824
- ]
825
- }
826
- ),
827
- /* @__PURE__ */ jsxs(Flex, { gap: 1, onClick: (e) => e.stopPropagation(), children: [
828
- /* @__PURE__ */ jsx(
829
- IconButton,
830
- {
831
- label: t("editor.step-up", "Move the step up"),
832
- onClick: () => moveStep(stepIndex, -1),
833
- disabled: stepIndex === 0,
834
- children: /* @__PURE__ */ jsx(ArrowUp, {})
835
- }
836
- ),
837
- /* @__PURE__ */ jsx(
838
- IconButton,
839
- {
840
- label: t("editor.step-down", "Move the step down"),
841
- onClick: () => moveStep(stepIndex, 1),
842
- disabled: stepIndex === definition.steps.length - 1,
843
- children: /* @__PURE__ */ jsx(ArrowDown, {})
844
- }
845
- ),
846
- /* @__PURE__ */ jsx(
847
- IconButton,
848
- {
849
- label: t("editor.step-delete", "Delete the step and its fields"),
850
- onClick: () => {
851
- setSelection({ kind: "form" });
852
- patchDefinition((steps) => steps.filter((s) => s.id !== step.id));
853
- },
854
- children: /* @__PURE__ */ jsx(Trash, {})
855
- }
856
- )
857
- ] })
858
- ] }),
859
- /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
860
- step.fields.map((field, fieldIndex) => {
861
- const flags = fieldFlags(field.id);
862
- const isSelected = selection.kind === "field" && selection.fieldId === field.id;
863
- return /* @__PURE__ */ jsx(
864
- Box,
865
- {
866
- background: isSelected ? "primary100" : "neutral100",
867
- hasRadius: true,
868
- padding: 3,
869
- onClick: (e) => {
870
- e.stopPropagation();
871
- setSelection({ kind: "field", fieldId: field.id });
872
- },
873
- style: { cursor: "pointer" },
874
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
875
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
876
- /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: field.label || field.name || "—" }),
877
- /* @__PURE__ */ jsx(Badge, { children: field.type }),
878
- field.required && /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral600", children: t("editor.required", "required") }),
879
- field.hubspot?.property && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
880
- field.hubspot.object ?? "contact",
881
- ".",
882
- field.hubspot.property
883
- ] }),
884
- field.visibleIf?.rules?.length ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "alternative100", textColor: "alternative700", children: t("editor.conditional", "Conditional") }) : null,
885
- (flags.error || flags.problem) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "danger100", textColor: "danger700", children: flags.error?.code ?? flags.problem?.code })
886
- ] }),
867
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", paddingBottom: 2, children: [
868
+ /* @__PURE__ */ jsxs(
869
+ Flex,
870
+ {
871
+ gap: 2,
872
+ alignItems: "center",
873
+ onClick: () => setSelection({ kind: "step", stepId: step.id }),
874
+ style: { cursor: "pointer" },
875
+ children: [
876
+ /* @__PURE__ */ jsx(
877
+ "span",
878
+ {
879
+ ...stepHandle.attributes,
880
+ ...stepHandle.listeners,
881
+ onClick: (e) => e.stopPropagation(),
882
+ style: { cursor: "grab", display: "inline-flex", color: "inherit" },
883
+ "aria-label": t("editor.drag-step", "Drag to reorder the step"),
884
+ children: /* @__PURE__ */ jsx(Drag, {})
885
+ }
886
+ ),
887
+ /* @__PURE__ */ jsxs(Typography, { variant: "delta", children: [
888
+ t("editor.step", "Step {n}", { n: stepIndex + 1 }),
889
+ step.title ? ` — ${step.title}` : ""
890
+ ] }),
891
+ step.visibleIf?.rules?.length ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "alternative100", textColor: "alternative700", children: t("editor.conditional", "Conditional") }) : null,
892
+ errors.some((e) => e.stepId === step.id) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "danger100", textColor: "danger700", children: t("editor.flag-error", "To fix") })
893
+ ]
894
+ }
895
+ ),
887
896
  /* @__PURE__ */ jsxs(Flex, { gap: 1, onClick: (e) => e.stopPropagation(), children: [
888
897
  /* @__PURE__ */ jsx(
889
898
  IconButton,
890
899
  {
891
- label: t("editor.field-up", "Move up"),
892
- onClick: () => moveField(stepIndex, fieldIndex, -1),
893
- disabled: stepIndex === 0 && fieldIndex === 0,
900
+ label: t("editor.step-up", "Move the step up"),
901
+ onClick: () => moveStep(stepIndex, -1),
902
+ disabled: stepIndex === 0,
894
903
  children: /* @__PURE__ */ jsx(ArrowUp, {})
895
904
  }
896
905
  ),
897
906
  /* @__PURE__ */ jsx(
898
907
  IconButton,
899
908
  {
900
- label: t("editor.field-down", "Move down"),
901
- onClick: () => moveField(stepIndex, fieldIndex, 1),
902
- disabled: stepIndex === definition.steps.length - 1 && fieldIndex === step.fields.length - 1,
909
+ label: t("editor.step-down", "Move the step down"),
910
+ onClick: () => moveStep(stepIndex, 1),
911
+ disabled: stepIndex === definition.steps.length - 1,
903
912
  children: /* @__PURE__ */ jsx(ArrowDown, {})
904
913
  }
905
914
  ),
906
915
  /* @__PURE__ */ jsx(
907
916
  IconButton,
908
917
  {
909
- label: t("editor.field-delete", "Delete the field"),
918
+ label: t("editor.step-delete", "Delete the step and its fields"),
910
919
  onClick: () => {
911
920
  setSelection({ kind: "form" });
912
- patchStep(step.id, {
913
- fields: step.fields.filter((f) => f.id !== field.id)
914
- });
921
+ patchDefinition((steps) => steps.filter((s) => s.id !== step.id));
915
922
  },
916
923
  children: /* @__PURE__ */ jsx(Trash, {})
917
924
  }
918
925
  )
919
926
  ] })
927
+ ] }),
928
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
929
+ /* @__PURE__ */ jsx(
930
+ SortableList,
931
+ {
932
+ ids: step.fields.map((f) => f.id),
933
+ onReorder: (ids) => patchStep(step.id, { fields: reorderByIds(step.fields, ids) }),
934
+ children: step.fields.map((field, fieldIndex) => {
935
+ const flags = fieldFlags(field.id);
936
+ const isSelected = selection.kind === "field" && selection.fieldId === field.id;
937
+ return /* @__PURE__ */ jsx(
938
+ SortableItem,
939
+ {
940
+ id: field.id,
941
+ children: (fieldHandle) => /* @__PURE__ */ jsx(
942
+ Box,
943
+ {
944
+ background: isSelected ? "primary100" : "neutral100",
945
+ hasRadius: true,
946
+ padding: 3,
947
+ onClick: (e) => {
948
+ e.stopPropagation();
949
+ setSelection({ kind: "field", fieldId: field.id });
950
+ },
951
+ style: { cursor: "pointer" },
952
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
953
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
954
+ /* @__PURE__ */ jsx(
955
+ "span",
956
+ {
957
+ ...fieldHandle.attributes,
958
+ ...fieldHandle.listeners,
959
+ onClick: (e) => e.stopPropagation(),
960
+ style: { cursor: "grab", display: "inline-flex" },
961
+ "aria-label": t("editor.drag-field", "Drag to reorder the field"),
962
+ children: /* @__PURE__ */ jsx(Drag, {})
963
+ }
964
+ ),
965
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: field.label || field.name || "—" }),
966
+ /* @__PURE__ */ jsx(Badge, { children: field.type }),
967
+ field.required && /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral600", children: t("editor.required", "required") }),
968
+ field.hubspot?.property && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
969
+ field.hubspot.object ?? "contact",
970
+ ".",
971
+ field.hubspot.property
972
+ ] }),
973
+ field.visibleIf?.rules?.length ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "alternative100", textColor: "alternative700", children: t("editor.conditional", "Conditional") }) : null,
974
+ (flags.error || flags.problem) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "danger100", textColor: "danger700", children: flags.error?.code ?? flags.problem?.code })
975
+ ] }),
976
+ /* @__PURE__ */ jsxs(Flex, { gap: 1, onClick: (e) => e.stopPropagation(), children: [
977
+ /* @__PURE__ */ jsx(
978
+ IconButton,
979
+ {
980
+ label: t("editor.field-up", "Move up"),
981
+ onClick: () => moveField(stepIndex, fieldIndex, -1),
982
+ disabled: stepIndex === 0 && fieldIndex === 0,
983
+ children: /* @__PURE__ */ jsx(ArrowUp, {})
984
+ }
985
+ ),
986
+ /* @__PURE__ */ jsx(
987
+ IconButton,
988
+ {
989
+ label: t("editor.field-down", "Move down"),
990
+ onClick: () => moveField(stepIndex, fieldIndex, 1),
991
+ disabled: stepIndex === definition.steps.length - 1 && fieldIndex === step.fields.length - 1,
992
+ children: /* @__PURE__ */ jsx(ArrowDown, {})
993
+ }
994
+ ),
995
+ /* @__PURE__ */ jsx(
996
+ IconButton,
997
+ {
998
+ label: t("editor.field-delete", "Delete the field"),
999
+ onClick: () => {
1000
+ setSelection({ kind: "form" });
1001
+ patchStep(step.id, {
1002
+ fields: step.fields.filter((f) => f.id !== field.id)
1003
+ });
1004
+ },
1005
+ children: /* @__PURE__ */ jsx(Trash, {})
1006
+ }
1007
+ )
1008
+ ] })
1009
+ ] })
1010
+ }
1011
+ )
1012
+ },
1013
+ field.id
1014
+ );
1015
+ })
1016
+ }
1017
+ ),
1018
+ /* @__PURE__ */ jsx(
1019
+ Button,
1020
+ {
1021
+ variant: "tertiary",
1022
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
1023
+ onClick: (e) => {
1024
+ e.stopPropagation();
1025
+ const field = newField(t("editor.new-field", "New field"));
1026
+ patchStep(step.id, { fields: [...step.fields, field] });
1027
+ setSelection({ kind: "field", fieldId: field.id });
1028
+ },
1029
+ children: t("editor.add-field", "Add a field")
1030
+ }
1031
+ )
920
1032
  ] })
921
- },
922
- field.id
923
- );
924
- }),
925
- /* @__PURE__ */ jsx(
926
- Button,
927
- {
928
- variant: "tertiary",
929
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
930
- onClick: (e) => {
931
- e.stopPropagation();
932
- const field = newField(t("editor.new-field", "New field"));
933
- patchStep(step.id, { fields: [...step.fields, field] });
934
- setSelection({ kind: "field", fieldId: field.id });
935
- },
936
- children: t("editor.add-field", "Add a field")
1033
+ ]
937
1034
  }
938
1035
  )
939
- ] })
940
- ]
941
- },
942
- step.id
943
- )),
1036
+ },
1037
+ step.id
1038
+ ))
1039
+ }
1040
+ ),
944
1041
  /* @__PURE__ */ jsx(
945
1042
  Button,
946
1043
  {