@orion-studios/payload-studio 0.6.0-beta.25 → 0.6.0-beta.26

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.
@@ -749,7 +749,7 @@ var init_OrionBlocksFieldImpl = __esm({
749
749
  const schemaPath = schemaPathFromProps ?? name;
750
750
  const minRows = minRowsProp ?? (required ? 1 : 0);
751
751
  const { setDocFieldPreferences } = (0, import_DocumentInfo.useDocumentInfo)();
752
- const { addFieldRow, dispatchFields, getFields, moveFieldRow, removeFieldRow, replaceState, setModified } = (0, import_Form.useForm)();
752
+ const { addFieldRow, dispatchFields, getFields: getFields2, moveFieldRow, removeFieldRow, replaceState, setModified } = (0, import_Form.useForm)();
753
753
  const { code: locale } = (0, import_Locale.useLocale)();
754
754
  const configContext = (0, import_Config.useConfig)();
755
755
  const config = configContext?.config ?? {};
@@ -911,7 +911,7 @@ var init_OrionBlocksFieldImpl = __esm({
911
911
  (rowIndex) => {
912
912
  const result = clipboardCopy({
913
913
  getDataToCopy: () => reduceFormStateByPath({
914
- formState: getFields(),
914
+ formState: getFields2(),
915
915
  path: safePath,
916
916
  rowIndex
917
917
  }),
@@ -929,13 +929,13 @@ var init_OrionBlocksFieldImpl = __esm({
929
929
  import_sonner.toast.success(t("general:copied"));
930
930
  }
931
931
  },
932
- [clientBlocks, getFields, safePath, t, type]
932
+ [clientBlocks, getFields2, safePath, t, type]
933
933
  );
934
934
  const pasteRow = (0, import_react10.useCallback)(
935
935
  (rowIndex) => {
936
936
  const result = clipboardPaste({
937
937
  onPaste: (dataFromClipboard) => {
938
- const formState = getFields();
938
+ const formState = getFields2();
939
939
  const newState = mergeFormStateFromClipboard({
940
940
  dataFromClipboard,
941
941
  formState,
@@ -952,11 +952,11 @@ var init_OrionBlocksFieldImpl = __esm({
952
952
  import_sonner.toast.error(result);
953
953
  }
954
954
  },
955
- [clientBlocks, getFields, replaceState, safePath, setModified, t]
955
+ [clientBlocks, getFields2, replaceState, safePath, setModified, t]
956
956
  );
957
957
  const pasteBlocks = (0, import_react10.useCallback)(
958
958
  (dataFromClipboard) => {
959
- const formState = getFields();
959
+ const formState = getFields2();
960
960
  const newState = mergeFormStateFromClipboard({
961
961
  dataFromClipboard,
962
962
  formState,
@@ -965,7 +965,7 @@ var init_OrionBlocksFieldImpl = __esm({
965
965
  replaceState(newState);
966
966
  setModified(true);
967
967
  },
968
- [getFields, replaceState, safePath, setModified]
968
+ [getFields2, replaceState, safePath, setModified]
969
969
  );
970
970
  const hasMaxRows = Boolean(maxRows && rows.length >= maxRows);
971
971
  const fieldErrorCount = errorPaths.length;
@@ -1042,7 +1042,7 @@ var init_OrionBlocksFieldImpl = __esm({
1042
1042
  className: `${baseClass}__header-action`,
1043
1043
  disabled,
1044
1044
  getDataToCopy: () => reduceFormStateByPath({
1045
- formState: getFields(),
1045
+ formState: getFields2(),
1046
1046
  path: safePath
1047
1047
  }),
1048
1048
  onPaste: pasteBlocks,
@@ -8258,15 +8258,11 @@ var getFormTitle2 = (value) => {
8258
8258
  // src/admin/components/studio/AdminStudioFormDetailView.tsx
8259
8259
  var import_jsx_runtime41 = require("react/jsx-runtime");
8260
8260
  var getNonEmptyText = (value, fallback = "") => typeof value === "string" && value.trim().length > 0 ? value : fallback;
8261
- var formatStepsText = (value) => {
8261
+ var normalizeSteps = (value) => {
8262
8262
  if (!Array.isArray(value)) {
8263
- return "[]";
8264
- }
8265
- try {
8266
- return JSON.stringify(value, null, 2);
8267
- } catch {
8268
- return "[]";
8263
+ return [];
8269
8264
  }
8265
+ return value.map((step) => step && typeof step === "object" && !Array.isArray(step) ? step : {});
8270
8266
  };
8271
8267
  var toEditorState = (doc) => {
8272
8268
  const emails = doc.emails && typeof doc.emails === "object" ? doc.emails : null;
@@ -8282,7 +8278,7 @@ var toEditorState = (doc) => {
8282
8278
  sendAdmin: emails?.sendAdmin !== false,
8283
8279
  sendConfirmation: emails?.sendConfirmation !== false,
8284
8280
  slug: getNonEmptyText(doc.slug),
8285
- stepsText: formatStepsText(doc.steps),
8281
+ steps: normalizeSteps(doc.steps),
8286
8282
  submitLabel: getNonEmptyText(doc.submitLabel, "Submit"),
8287
8283
  successMessage: getNonEmptyText(doc.successMessage),
8288
8284
  title: getNonEmptyText(doc.title, "Untitled Form")
@@ -8293,25 +8289,54 @@ var checkboxLabelStyle = {
8293
8289
  display: "flex",
8294
8290
  gap: "0.6rem"
8295
8291
  };
8296
- var codeStyle = {
8297
- background: "color-mix(in srgb, var(--orion-admin-card-bg) 82%, black)",
8298
- border: "1px solid var(--orion-admin-card-border)",
8299
- borderRadius: "var(--orion-admin-radius-sm)",
8300
- color: "var(--orion-admin-text)",
8301
- fontFamily: "ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, monospace",
8302
- fontSize: "0.86rem",
8303
- lineHeight: 1.55,
8304
- margin: 0,
8305
- maxHeight: "28rem",
8306
- overflow: "auto",
8307
- padding: "0.9rem",
8308
- whiteSpace: "pre-wrap"
8309
- };
8310
8292
  var sectionGridStyle = {
8311
8293
  display: "grid",
8312
8294
  gap: "1rem",
8313
8295
  gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
8314
8296
  };
8297
+ var fieldTypeOptions = [
8298
+ "text",
8299
+ "textarea",
8300
+ "email",
8301
+ "phone",
8302
+ "url",
8303
+ "select",
8304
+ "radio",
8305
+ "checkbox",
8306
+ "checkbox-group",
8307
+ "date",
8308
+ "file"
8309
+ ];
8310
+ var getFields = (step) => Array.isArray(step.fields) ? step.fields.map(
8311
+ (field) => field && typeof field === "object" && !Array.isArray(field) ? field : {}
8312
+ ) : [];
8313
+ var toOptionsText = (value) => Array.isArray(value) ? value.map((entry) => {
8314
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
8315
+ const record = entry;
8316
+ const label = typeof record.label === "string" ? record.label : "";
8317
+ const optionValue = typeof record.value === "string" ? record.value : label;
8318
+ return label && optionValue && label !== optionValue ? `${label} | ${optionValue}` : label || optionValue;
8319
+ }
8320
+ return typeof entry === "string" ? entry : "";
8321
+ }).filter(Boolean).join("\n") : "";
8322
+ var fromOptionsText = (value) => value.split("\n").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
8323
+ const [label, optionValue] = entry.split("|").map((part) => part.trim());
8324
+ return {
8325
+ label,
8326
+ value: optionValue || label
8327
+ };
8328
+ });
8329
+ var slugifyFieldName = (value) => value.trim().replace(/[^a-z0-9]+/gi, " ").trim().replace(/\s+([a-z0-9])/gi, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toLowerCase());
8330
+ var blankField = () => ({
8331
+ label: "New field",
8332
+ name: "newField",
8333
+ required: false,
8334
+ type: "text"
8335
+ });
8336
+ var blankStep = () => ({
8337
+ fields: [blankField()],
8338
+ title: "New step"
8339
+ });
8315
8340
  function getFormIDFromPathname(pathname) {
8316
8341
  const marker = "/forms/";
8317
8342
  const raw = getIDFromPathname(pathname, marker);
@@ -8404,10 +8429,6 @@ function AdminStudioFormDetailView(props) {
8404
8429
  setError(null);
8405
8430
  setSavedMessage(null);
8406
8431
  try {
8407
- const parsedSteps = JSON.parse(editorState.stepsText);
8408
- if (!Array.isArray(parsedSteps)) {
8409
- throw new Error("Structure JSON must be an array of steps.");
8410
- }
8411
8432
  const payload = {
8412
8433
  emails: {
8413
8434
  adminRecipients: editorState.adminRecipientsText.split("\n").map((value) => value.trim()).filter(Boolean).map((email) => ({ email })),
@@ -8419,7 +8440,7 @@ function AdminStudioFormDetailView(props) {
8419
8440
  sendConfirmation: editorState.sendConfirmation
8420
8441
  },
8421
8442
  slug: editorState.slug.trim(),
8422
- steps: parsedSteps,
8443
+ steps: editorState.steps,
8423
8444
  submitLabel: editorState.submitLabel.trim(),
8424
8445
  successMessage: editorState.successMessage,
8425
8446
  title: editorState.title.trim()
@@ -8465,8 +8486,33 @@ function AdminStudioFormDetailView(props) {
8465
8486
  const toneStyle = getFormToneStyle2(slug, title || formID || "form");
8466
8487
  const fieldLabels = doc ? buildFieldLabelMap2(doc) : /* @__PURE__ */ new Map();
8467
8488
  const latestSubmission = submissions[0];
8468
- const stepCount = doc && Array.isArray(doc.steps) ? doc.steps.length : 0;
8469
- const fieldCount = doc ? getFieldCount2(doc) : 0;
8489
+ const stepCount = editorState?.steps.length || 0;
8490
+ const fieldCount = editorState ? editorState.steps.reduce((count, step) => count + getFields(step).length, 0) : doc ? getFieldCount2(doc) : 0;
8491
+ const updateStep = (stepIndex, patch) => {
8492
+ setEditorState(
8493
+ (current) => current ? {
8494
+ ...current,
8495
+ steps: current.steps.map(
8496
+ (step, index) => index === stepIndex ? { ...step, ...patch } : step
8497
+ )
8498
+ } : current
8499
+ );
8500
+ };
8501
+ const updateField = (stepIndex, fieldIndex, patch) => {
8502
+ setEditorState((current) => {
8503
+ if (!current) return current;
8504
+ return {
8505
+ ...current,
8506
+ steps: current.steps.map((step, index) => {
8507
+ if (index !== stepIndex) return step;
8508
+ const fields = getFields(step).map(
8509
+ (field, currentFieldIndex) => currentFieldIndex === fieldIndex ? { ...field, ...patch } : field
8510
+ );
8511
+ return { ...step, fields };
8512
+ })
8513
+ };
8514
+ });
8515
+ };
8470
8516
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8471
8517
  AdminPage,
8472
8518
  {
@@ -8545,10 +8591,9 @@ function AdminStudioFormDetailView(props) {
8545
8591
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
8546
8592
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8547
8593
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Step preview" }),
8548
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Review the configured workflow structure before editing the JSON source." }),
8549
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: Array.isArray(doc.steps) && doc.steps.length > 0 ? doc.steps.map((step, stepIndex) => {
8550
- const record = step && typeof step === "object" && !Array.isArray(step) ? step : null;
8551
- const fields = Array.isArray(record?.fields) ? record.fields : [];
8594
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Review the public workflow as visitors will move through it." }),
8595
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: editorState.steps.length > 0 ? editorState.steps.map((record, stepIndex) => {
8596
+ const fields = getFields(record);
8552
8597
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form", children: [
8553
8598
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8554
8599
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("strong", { children: [
@@ -8600,7 +8645,7 @@ function AdminStudioFormDetailView(props) {
8600
8645
  ] }, `step-${stepIndex}`);
8601
8646
  }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8602
8647
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No steps configured" }),
8603
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add at least one step in the JSON editor to publish this form." })
8648
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add at least one step in Form settings to publish this form." })
8604
8649
  ] }) })
8605
8650
  ] }),
8606
8651
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
@@ -8782,32 +8827,226 @@ function AdminStudioFormDetailView(props) {
8782
8827
  ] })
8783
8828
  ] })
8784
8829
  ] }),
8785
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8786
- "Structure JSON",
8787
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8788
- "textarea",
8789
- {
8790
- onChange: (event) => setEditorState(
8791
- (current) => current ? { ...current, stepsText: event.target.value } : current
8792
- ),
8793
- rows: 18,
8794
- spellCheck: false,
8795
- style: {
8796
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
8797
- minHeight: "24rem"
8798
- },
8799
- value: editorState.stepsText
8800
- }
8801
- )
8830
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8831
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Form steps" }),
8832
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Edit the public workflow with plain labels and field settings." }),
8833
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem", marginTop: "1rem" }, children: [
8834
+ editorState.steps.map((step, stepIndex) => {
8835
+ const fields = getFields(step);
8836
+ const title2 = getNonEmptyText(step.title, `Step ${stepIndex + 1}`);
8837
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form", children: [
8838
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-inline-actions", style: { justifyContent: "space-between" }, children: [
8839
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: title2 }),
8840
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8841
+ "button",
8842
+ {
8843
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8844
+ onClick: () => setEditorState(
8845
+ (current) => current ? {
8846
+ ...current,
8847
+ steps: current.steps.filter((_, index) => index !== stepIndex)
8848
+ } : current
8849
+ ),
8850
+ type: "button",
8851
+ children: "Remove step"
8852
+ }
8853
+ )
8854
+ ] }),
8855
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8856
+ "Step title",
8857
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8858
+ "input",
8859
+ {
8860
+ onChange: (event) => updateStep(stepIndex, { title: event.target.value }),
8861
+ type: "text",
8862
+ value: getNonEmptyText(step.title)
8863
+ }
8864
+ )
8865
+ ] }),
8866
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8867
+ "Step intro text",
8868
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8869
+ "textarea",
8870
+ {
8871
+ onChange: (event) => updateStep(stepIndex, { subtitle: event.target.value }),
8872
+ rows: 3,
8873
+ value: getNonEmptyText(step.subtitle)
8874
+ }
8875
+ )
8876
+ ] }),
8877
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8878
+ "Next button label",
8879
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8880
+ "input",
8881
+ {
8882
+ onChange: (event) => updateStep(stepIndex, { nextLabel: event.target.value }),
8883
+ placeholder: "Next",
8884
+ type: "text",
8885
+ value: getNonEmptyText(step.nextLabel)
8886
+ }
8887
+ )
8888
+ ] }),
8889
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8890
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8891
+ "input",
8892
+ {
8893
+ checked: step.allowSkip === true,
8894
+ onChange: (event) => updateStep(stepIndex, { allowSkip: event.target.checked }),
8895
+ type: "checkbox"
8896
+ }
8897
+ ),
8898
+ "Allow visitors to skip this step"
8899
+ ] }),
8900
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "0.85rem" }, children: [
8901
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Fields" }),
8902
+ fields.map((field, fieldIndex) => {
8903
+ const label = getNonEmptyText(field.label, `Field ${fieldIndex + 1}`);
8904
+ const fieldType = getNonEmptyText(field.type, "text");
8905
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8906
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8907
+ "div",
8908
+ {
8909
+ className: "orion-admin-inline-actions",
8910
+ style: { justifyContent: "space-between" },
8911
+ children: [
8912
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: label }),
8913
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8914
+ "button",
8915
+ {
8916
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8917
+ onClick: () => setEditorState((current) => {
8918
+ if (!current) return current;
8919
+ return {
8920
+ ...current,
8921
+ steps: current.steps.map(
8922
+ (currentStep, index) => index === stepIndex ? {
8923
+ ...currentStep,
8924
+ fields: getFields(currentStep).filter(
8925
+ (_, currentFieldIndex) => currentFieldIndex !== fieldIndex
8926
+ )
8927
+ } : currentStep
8928
+ )
8929
+ };
8930
+ }),
8931
+ type: "button",
8932
+ children: "Remove field"
8933
+ }
8934
+ )
8935
+ ]
8936
+ }
8937
+ ),
8938
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8939
+ "Field label",
8940
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8941
+ "input",
8942
+ {
8943
+ onChange: (event) => {
8944
+ const nextLabel = event.target.value;
8945
+ const currentName = getNonEmptyText(field.name);
8946
+ updateField(stepIndex, fieldIndex, {
8947
+ label: nextLabel,
8948
+ name: currentName || slugifyFieldName(nextLabel)
8949
+ });
8950
+ },
8951
+ type: "text",
8952
+ value: label
8953
+ }
8954
+ )
8955
+ ] }),
8956
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8957
+ "Field key",
8958
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8959
+ "input",
8960
+ {
8961
+ onChange: (event) => updateField(stepIndex, fieldIndex, { name: event.target.value }),
8962
+ type: "text",
8963
+ value: getNonEmptyText(field.name)
8964
+ }
8965
+ )
8966
+ ] }),
8967
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8968
+ "Field type",
8969
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8970
+ "select",
8971
+ {
8972
+ onChange: (event) => updateField(stepIndex, fieldIndex, { type: event.target.value }),
8973
+ value: fieldType,
8974
+ children: fieldTypeOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: option, children: option }, option))
8975
+ }
8976
+ )
8977
+ ] }),
8978
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8979
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8980
+ "input",
8981
+ {
8982
+ checked: field.required === true,
8983
+ onChange: (event) => updateField(stepIndex, fieldIndex, { required: event.target.checked }),
8984
+ type: "checkbox"
8985
+ }
8986
+ ),
8987
+ "Required"
8988
+ ] }),
8989
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8990
+ "Help text",
8991
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8992
+ "textarea",
8993
+ {
8994
+ onChange: (event) => updateField(stepIndex, fieldIndex, { helpText: event.target.value }),
8995
+ rows: 2,
8996
+ value: getNonEmptyText(field.helpText)
8997
+ }
8998
+ )
8999
+ ] }),
9000
+ ["select", "radio", "checkbox-group"].includes(fieldType) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9001
+ "Options",
9002
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
9003
+ "textarea",
9004
+ {
9005
+ onChange: (event) => updateField(stepIndex, fieldIndex, {
9006
+ options: fromOptionsText(event.target.value)
9007
+ }),
9008
+ placeholder: "Option one\nOption two",
9009
+ rows: 4,
9010
+ value: toOptionsText(field.options)
9011
+ }
9012
+ )
9013
+ ] }) : null
9014
+ ] }, `edit-field-${stepIndex}-${fieldIndex}`);
9015
+ }),
9016
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
9017
+ "button",
9018
+ {
9019
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
9020
+ onClick: () => setEditorState(
9021
+ (current) => current ? {
9022
+ ...current,
9023
+ steps: current.steps.map(
9024
+ (currentStep, index) => index === stepIndex ? { ...currentStep, fields: [...getFields(currentStep), blankField()] } : currentStep
9025
+ )
9026
+ } : current
9027
+ ),
9028
+ type: "button",
9029
+ children: "Add field"
9030
+ }
9031
+ )
9032
+ ] })
9033
+ ] }, `edit-step-${stepIndex}`);
9034
+ }),
9035
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
9036
+ "button",
9037
+ {
9038
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
9039
+ onClick: () => setEditorState(
9040
+ (current) => current ? { ...current, steps: [...current.steps, blankStep()] } : current
9041
+ ),
9042
+ type: "button",
9043
+ children: "Add step"
9044
+ }
9045
+ )
9046
+ ] })
8802
9047
  ] }),
8803
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "Edit the public workflow as JSON. The saved payload must remain an array of step objects compatible with the form collection schema." }),
8804
9048
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Form" })
8805
9049
  ] })
8806
- ] }),
8807
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8808
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Current structure payload" }),
8809
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Reference snapshot of the form steps that will be written back on save." }),
8810
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("pre", { style: { ...codeStyle, marginTop: "1rem" }, children: editorState.stepsText })
8811
9050
  ] })
8812
9051
  ] }) : null
8813
9052
  ]
@@ -8819,25 +9058,17 @@ function AdminStudioFormDetailView(props) {
8819
9058
  var import_link5 = __toESM(require("next/link"));
8820
9059
  var import_react33 = require("react");
8821
9060
  var import_jsx_runtime42 = require("react/jsx-runtime");
8822
- var codeStyle2 = {
8823
- background: "color-mix(in srgb, var(--orion-admin-card-bg) 82%, black)",
8824
- border: "1px solid var(--orion-admin-card-border)",
8825
- borderRadius: "var(--orion-admin-radius-sm)",
8826
- color: "var(--orion-admin-text)",
8827
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
8828
- fontSize: "0.86rem",
8829
- lineHeight: 1.55,
8830
- margin: 0,
8831
- maxHeight: "28rem",
8832
- overflow: "auto",
8833
- padding: "0.9rem",
8834
- whiteSpace: "pre-wrap"
8835
- };
8836
9061
  var sectionGridStyle2 = {
8837
9062
  display: "grid",
8838
9063
  gap: "1rem",
8839
9064
  gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
8840
9065
  };
9066
+ var nestedListStyle = {
9067
+ display: "grid",
9068
+ gap: "0.45rem",
9069
+ margin: 0,
9070
+ padding: 0
9071
+ };
8841
9072
  var renderFieldValue = (value) => {
8842
9073
  if (value === null || value === void 0) {
8843
9074
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
@@ -8851,7 +9082,26 @@ var renderFieldValue = (value) => {
8851
9082
  if (typeof value === "string") {
8852
9083
  return value.trim().length > 0 ? value : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
8853
9084
  }
8854
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("pre", { style: codeStyle2, children: JSON.stringify(value, null, 2) });
9085
+ if (Array.isArray(value)) {
9086
+ const entries = value.filter((entry) => entry !== null && entry !== void 0 && entry !== "");
9087
+ if (entries.length === 0) {
9088
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9089
+ }
9090
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { style: nestedListStyle, children: entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: renderFieldValue(entry) }, index)) });
9091
+ }
9092
+ if (typeof value === "object") {
9093
+ const entries = Object.entries(value).filter(
9094
+ ([, entryValue]) => entryValue !== null && entryValue !== void 0 && entryValue !== ""
9095
+ );
9096
+ if (entries.length === 0) {
9097
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9098
+ }
9099
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.65rem" }, children: entries.map(([key, entryValue]) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9100
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: humanizeKey2(key) }),
9101
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: renderFieldValue(entryValue) })
9102
+ ] }, key)) });
9103
+ }
9104
+ return String(value);
8855
9105
  };
8856
9106
  function getSubmissionIDFromPathname(pathname) {
8857
9107
  return getIDFromPathname(pathname, "/forms/submissions/");
@@ -9003,31 +9253,24 @@ function AdminStudioFormSubmissionView(props) {
9003
9253
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9004
9254
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Highlighted answers" }),
9005
9255
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: previewFields.length }),
9006
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Readable answer previews surfaced from the structured payload." })
9256
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Readable answer previews from this response." })
9007
9257
  ] })
9008
9258
  ] }),
9009
9259
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: sectionGridStyle2, children: [
9010
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9011
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9012
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Response details" }),
9013
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Formatted answers using the current form field labels when available." }),
9014
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-form", children: [
9015
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9016
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
9017
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: key })
9018
- ] }),
9019
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { children: renderFieldValue(value) })
9020
- ] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9021
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No response payload" }),
9022
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This submission does not contain a structured data object." })
9023
- ] }) })
9024
- ] }),
9025
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9026
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Raw payload" }),
9027
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Verbatim submission data for troubleshooting or export checks." }),
9028
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("pre", { style: { ...codeStyle2, marginTop: "1rem" }, children: JSON.stringify(doc.data ?? {}, null, 2) })
9029
- ] })
9030
- ] }),
9260
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9261
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Response details" }),
9262
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Formatted answers using the current form field labels when available." }),
9263
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-form", children: [
9264
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9265
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
9266
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: key })
9267
+ ] }),
9268
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { children: renderFieldValue(value) })
9269
+ ] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9270
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No answers available" }),
9271
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This submission does not contain visible response details." })
9272
+ ] }) })
9273
+ ] }) }),
9031
9274
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9032
9275
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card orion-admin-meta-table", children: [
9033
9276
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
@@ -5928,15 +5928,11 @@ var getFormTitle2 = (value) => {
5928
5928
  // src/admin/components/studio/AdminStudioFormDetailView.tsx
5929
5929
  import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
5930
5930
  var getNonEmptyText = (value, fallback = "") => typeof value === "string" && value.trim().length > 0 ? value : fallback;
5931
- var formatStepsText = (value) => {
5931
+ var normalizeSteps = (value) => {
5932
5932
  if (!Array.isArray(value)) {
5933
- return "[]";
5934
- }
5935
- try {
5936
- return JSON.stringify(value, null, 2);
5937
- } catch {
5938
- return "[]";
5933
+ return [];
5939
5934
  }
5935
+ return value.map((step) => step && typeof step === "object" && !Array.isArray(step) ? step : {});
5940
5936
  };
5941
5937
  var toEditorState = (doc) => {
5942
5938
  const emails = doc.emails && typeof doc.emails === "object" ? doc.emails : null;
@@ -5952,7 +5948,7 @@ var toEditorState = (doc) => {
5952
5948
  sendAdmin: emails?.sendAdmin !== false,
5953
5949
  sendConfirmation: emails?.sendConfirmation !== false,
5954
5950
  slug: getNonEmptyText(doc.slug),
5955
- stepsText: formatStepsText(doc.steps),
5951
+ steps: normalizeSteps(doc.steps),
5956
5952
  submitLabel: getNonEmptyText(doc.submitLabel, "Submit"),
5957
5953
  successMessage: getNonEmptyText(doc.successMessage),
5958
5954
  title: getNonEmptyText(doc.title, "Untitled Form")
@@ -5963,25 +5959,54 @@ var checkboxLabelStyle = {
5963
5959
  display: "flex",
5964
5960
  gap: "0.6rem"
5965
5961
  };
5966
- var codeStyle = {
5967
- background: "color-mix(in srgb, var(--orion-admin-card-bg) 82%, black)",
5968
- border: "1px solid var(--orion-admin-card-border)",
5969
- borderRadius: "var(--orion-admin-radius-sm)",
5970
- color: "var(--orion-admin-text)",
5971
- fontFamily: "ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, monospace",
5972
- fontSize: "0.86rem",
5973
- lineHeight: 1.55,
5974
- margin: 0,
5975
- maxHeight: "28rem",
5976
- overflow: "auto",
5977
- padding: "0.9rem",
5978
- whiteSpace: "pre-wrap"
5979
- };
5980
5962
  var sectionGridStyle = {
5981
5963
  display: "grid",
5982
5964
  gap: "1rem",
5983
5965
  gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
5984
5966
  };
5967
+ var fieldTypeOptions = [
5968
+ "text",
5969
+ "textarea",
5970
+ "email",
5971
+ "phone",
5972
+ "url",
5973
+ "select",
5974
+ "radio",
5975
+ "checkbox",
5976
+ "checkbox-group",
5977
+ "date",
5978
+ "file"
5979
+ ];
5980
+ var getFields = (step) => Array.isArray(step.fields) ? step.fields.map(
5981
+ (field) => field && typeof field === "object" && !Array.isArray(field) ? field : {}
5982
+ ) : [];
5983
+ var toOptionsText = (value) => Array.isArray(value) ? value.map((entry) => {
5984
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
5985
+ const record = entry;
5986
+ const label = typeof record.label === "string" ? record.label : "";
5987
+ const optionValue = typeof record.value === "string" ? record.value : label;
5988
+ return label && optionValue && label !== optionValue ? `${label} | ${optionValue}` : label || optionValue;
5989
+ }
5990
+ return typeof entry === "string" ? entry : "";
5991
+ }).filter(Boolean).join("\n") : "";
5992
+ var fromOptionsText = (value) => value.split("\n").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
5993
+ const [label, optionValue] = entry.split("|").map((part) => part.trim());
5994
+ return {
5995
+ label,
5996
+ value: optionValue || label
5997
+ };
5998
+ });
5999
+ var slugifyFieldName = (value) => value.trim().replace(/[^a-z0-9]+/gi, " ").trim().replace(/\s+([a-z0-9])/gi, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toLowerCase());
6000
+ var blankField = () => ({
6001
+ label: "New field",
6002
+ name: "newField",
6003
+ required: false,
6004
+ type: "text"
6005
+ });
6006
+ var blankStep = () => ({
6007
+ fields: [blankField()],
6008
+ title: "New step"
6009
+ });
5985
6010
  function getFormIDFromPathname(pathname) {
5986
6011
  const marker = "/forms/";
5987
6012
  const raw = getIDFromPathname(pathname, marker);
@@ -6074,10 +6099,6 @@ function AdminStudioFormDetailView(props) {
6074
6099
  setError(null);
6075
6100
  setSavedMessage(null);
6076
6101
  try {
6077
- const parsedSteps = JSON.parse(editorState.stepsText);
6078
- if (!Array.isArray(parsedSteps)) {
6079
- throw new Error("Structure JSON must be an array of steps.");
6080
- }
6081
6102
  const payload = {
6082
6103
  emails: {
6083
6104
  adminRecipients: editorState.adminRecipientsText.split("\n").map((value) => value.trim()).filter(Boolean).map((email) => ({ email })),
@@ -6089,7 +6110,7 @@ function AdminStudioFormDetailView(props) {
6089
6110
  sendConfirmation: editorState.sendConfirmation
6090
6111
  },
6091
6112
  slug: editorState.slug.trim(),
6092
- steps: parsedSteps,
6113
+ steps: editorState.steps,
6093
6114
  submitLabel: editorState.submitLabel.trim(),
6094
6115
  successMessage: editorState.successMessage,
6095
6116
  title: editorState.title.trim()
@@ -6135,8 +6156,33 @@ function AdminStudioFormDetailView(props) {
6135
6156
  const toneStyle = getFormToneStyle2(slug, title || formID || "form");
6136
6157
  const fieldLabels = doc ? buildFieldLabelMap2(doc) : /* @__PURE__ */ new Map();
6137
6158
  const latestSubmission = submissions[0];
6138
- const stepCount = doc && Array.isArray(doc.steps) ? doc.steps.length : 0;
6139
- const fieldCount = doc ? getFieldCount2(doc) : 0;
6159
+ const stepCount = editorState?.steps.length || 0;
6160
+ const fieldCount = editorState ? editorState.steps.reduce((count, step) => count + getFields(step).length, 0) : doc ? getFieldCount2(doc) : 0;
6161
+ const updateStep = (stepIndex, patch) => {
6162
+ setEditorState(
6163
+ (current) => current ? {
6164
+ ...current,
6165
+ steps: current.steps.map(
6166
+ (step, index) => index === stepIndex ? { ...step, ...patch } : step
6167
+ )
6168
+ } : current
6169
+ );
6170
+ };
6171
+ const updateField = (stepIndex, fieldIndex, patch) => {
6172
+ setEditorState((current) => {
6173
+ if (!current) return current;
6174
+ return {
6175
+ ...current,
6176
+ steps: current.steps.map((step, index) => {
6177
+ if (index !== stepIndex) return step;
6178
+ const fields = getFields(step).map(
6179
+ (field, currentFieldIndex) => currentFieldIndex === fieldIndex ? { ...field, ...patch } : field
6180
+ );
6181
+ return { ...step, fields };
6182
+ })
6183
+ };
6184
+ });
6185
+ };
6140
6186
  return /* @__PURE__ */ jsx30(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs27(
6141
6187
  AdminPage,
6142
6188
  {
@@ -6215,10 +6261,9 @@ function AdminStudioFormDetailView(props) {
6215
6261
  /* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "1rem" }, children: [
6216
6262
  /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
6217
6263
  /* @__PURE__ */ jsx30("strong", { children: "Step preview" }),
6218
- /* @__PURE__ */ jsx30("span", { children: "Review the configured workflow structure before editing the JSON source." }),
6219
- /* @__PURE__ */ jsx30("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: Array.isArray(doc.steps) && doc.steps.length > 0 ? doc.steps.map((step, stepIndex) => {
6220
- const record = step && typeof step === "object" && !Array.isArray(step) ? step : null;
6221
- const fields = Array.isArray(record?.fields) ? record.fields : [];
6264
+ /* @__PURE__ */ jsx30("span", { children: "Review the public workflow as visitors will move through it." }),
6265
+ /* @__PURE__ */ jsx30("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: editorState.steps.length > 0 ? editorState.steps.map((record, stepIndex) => {
6266
+ const fields = getFields(record);
6222
6267
  return /* @__PURE__ */ jsxs27("div", { className: "orion-admin-form", children: [
6223
6268
  /* @__PURE__ */ jsxs27("div", { children: [
6224
6269
  /* @__PURE__ */ jsxs27("strong", { children: [
@@ -6270,7 +6315,7 @@ function AdminStudioFormDetailView(props) {
6270
6315
  ] }, `step-${stepIndex}`);
6271
6316
  }) : /* @__PURE__ */ jsxs27("div", { className: "orion-admin-empty-state", children: [
6272
6317
  /* @__PURE__ */ jsx30("strong", { children: "No steps configured" }),
6273
- /* @__PURE__ */ jsx30("span", { children: "Add at least one step in the JSON editor to publish this form." })
6318
+ /* @__PURE__ */ jsx30("span", { children: "Add at least one step in Form settings to publish this form." })
6274
6319
  ] }) })
6275
6320
  ] }),
6276
6321
  /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
@@ -6452,32 +6497,226 @@ function AdminStudioFormDetailView(props) {
6452
6497
  ] })
6453
6498
  ] })
6454
6499
  ] }),
6455
- /* @__PURE__ */ jsxs27("label", { children: [
6456
- "Structure JSON",
6457
- /* @__PURE__ */ jsx30(
6458
- "textarea",
6459
- {
6460
- onChange: (event) => setEditorState(
6461
- (current) => current ? { ...current, stepsText: event.target.value } : current
6462
- ),
6463
- rows: 18,
6464
- spellCheck: false,
6465
- style: {
6466
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
6467
- minHeight: "24rem"
6468
- },
6469
- value: editorState.stepsText
6470
- }
6471
- )
6500
+ /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
6501
+ /* @__PURE__ */ jsx30("strong", { children: "Form steps" }),
6502
+ /* @__PURE__ */ jsx30("span", { children: "Edit the public workflow with plain labels and field settings." }),
6503
+ /* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "1rem", marginTop: "1rem" }, children: [
6504
+ editorState.steps.map((step, stepIndex) => {
6505
+ const fields = getFields(step);
6506
+ const title2 = getNonEmptyText(step.title, `Step ${stepIndex + 1}`);
6507
+ return /* @__PURE__ */ jsxs27("div", { className: "orion-admin-form", children: [
6508
+ /* @__PURE__ */ jsxs27("div", { className: "orion-admin-inline-actions", style: { justifyContent: "space-between" }, children: [
6509
+ /* @__PURE__ */ jsx30("strong", { children: title2 }),
6510
+ /* @__PURE__ */ jsx30(
6511
+ "button",
6512
+ {
6513
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
6514
+ onClick: () => setEditorState(
6515
+ (current) => current ? {
6516
+ ...current,
6517
+ steps: current.steps.filter((_, index) => index !== stepIndex)
6518
+ } : current
6519
+ ),
6520
+ type: "button",
6521
+ children: "Remove step"
6522
+ }
6523
+ )
6524
+ ] }),
6525
+ /* @__PURE__ */ jsxs27("label", { children: [
6526
+ "Step title",
6527
+ /* @__PURE__ */ jsx30(
6528
+ "input",
6529
+ {
6530
+ onChange: (event) => updateStep(stepIndex, { title: event.target.value }),
6531
+ type: "text",
6532
+ value: getNonEmptyText(step.title)
6533
+ }
6534
+ )
6535
+ ] }),
6536
+ /* @__PURE__ */ jsxs27("label", { children: [
6537
+ "Step intro text",
6538
+ /* @__PURE__ */ jsx30(
6539
+ "textarea",
6540
+ {
6541
+ onChange: (event) => updateStep(stepIndex, { subtitle: event.target.value }),
6542
+ rows: 3,
6543
+ value: getNonEmptyText(step.subtitle)
6544
+ }
6545
+ )
6546
+ ] }),
6547
+ /* @__PURE__ */ jsxs27("label", { children: [
6548
+ "Next button label",
6549
+ /* @__PURE__ */ jsx30(
6550
+ "input",
6551
+ {
6552
+ onChange: (event) => updateStep(stepIndex, { nextLabel: event.target.value }),
6553
+ placeholder: "Next",
6554
+ type: "text",
6555
+ value: getNonEmptyText(step.nextLabel)
6556
+ }
6557
+ )
6558
+ ] }),
6559
+ /* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
6560
+ /* @__PURE__ */ jsx30(
6561
+ "input",
6562
+ {
6563
+ checked: step.allowSkip === true,
6564
+ onChange: (event) => updateStep(stepIndex, { allowSkip: event.target.checked }),
6565
+ type: "checkbox"
6566
+ }
6567
+ ),
6568
+ "Allow visitors to skip this step"
6569
+ ] }),
6570
+ /* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "0.85rem" }, children: [
6571
+ /* @__PURE__ */ jsx30("strong", { children: "Fields" }),
6572
+ fields.map((field, fieldIndex) => {
6573
+ const label = getNonEmptyText(field.label, `Field ${fieldIndex + 1}`);
6574
+ const fieldType = getNonEmptyText(field.type, "text");
6575
+ return /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
6576
+ /* @__PURE__ */ jsxs27(
6577
+ "div",
6578
+ {
6579
+ className: "orion-admin-inline-actions",
6580
+ style: { justifyContent: "space-between" },
6581
+ children: [
6582
+ /* @__PURE__ */ jsx30("strong", { children: label }),
6583
+ /* @__PURE__ */ jsx30(
6584
+ "button",
6585
+ {
6586
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
6587
+ onClick: () => setEditorState((current) => {
6588
+ if (!current) return current;
6589
+ return {
6590
+ ...current,
6591
+ steps: current.steps.map(
6592
+ (currentStep, index) => index === stepIndex ? {
6593
+ ...currentStep,
6594
+ fields: getFields(currentStep).filter(
6595
+ (_, currentFieldIndex) => currentFieldIndex !== fieldIndex
6596
+ )
6597
+ } : currentStep
6598
+ )
6599
+ };
6600
+ }),
6601
+ type: "button",
6602
+ children: "Remove field"
6603
+ }
6604
+ )
6605
+ ]
6606
+ }
6607
+ ),
6608
+ /* @__PURE__ */ jsxs27("label", { children: [
6609
+ "Field label",
6610
+ /* @__PURE__ */ jsx30(
6611
+ "input",
6612
+ {
6613
+ onChange: (event) => {
6614
+ const nextLabel = event.target.value;
6615
+ const currentName = getNonEmptyText(field.name);
6616
+ updateField(stepIndex, fieldIndex, {
6617
+ label: nextLabel,
6618
+ name: currentName || slugifyFieldName(nextLabel)
6619
+ });
6620
+ },
6621
+ type: "text",
6622
+ value: label
6623
+ }
6624
+ )
6625
+ ] }),
6626
+ /* @__PURE__ */ jsxs27("label", { children: [
6627
+ "Field key",
6628
+ /* @__PURE__ */ jsx30(
6629
+ "input",
6630
+ {
6631
+ onChange: (event) => updateField(stepIndex, fieldIndex, { name: event.target.value }),
6632
+ type: "text",
6633
+ value: getNonEmptyText(field.name)
6634
+ }
6635
+ )
6636
+ ] }),
6637
+ /* @__PURE__ */ jsxs27("label", { children: [
6638
+ "Field type",
6639
+ /* @__PURE__ */ jsx30(
6640
+ "select",
6641
+ {
6642
+ onChange: (event) => updateField(stepIndex, fieldIndex, { type: event.target.value }),
6643
+ value: fieldType,
6644
+ children: fieldTypeOptions.map((option) => /* @__PURE__ */ jsx30("option", { value: option, children: option }, option))
6645
+ }
6646
+ )
6647
+ ] }),
6648
+ /* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
6649
+ /* @__PURE__ */ jsx30(
6650
+ "input",
6651
+ {
6652
+ checked: field.required === true,
6653
+ onChange: (event) => updateField(stepIndex, fieldIndex, { required: event.target.checked }),
6654
+ type: "checkbox"
6655
+ }
6656
+ ),
6657
+ "Required"
6658
+ ] }),
6659
+ /* @__PURE__ */ jsxs27("label", { children: [
6660
+ "Help text",
6661
+ /* @__PURE__ */ jsx30(
6662
+ "textarea",
6663
+ {
6664
+ onChange: (event) => updateField(stepIndex, fieldIndex, { helpText: event.target.value }),
6665
+ rows: 2,
6666
+ value: getNonEmptyText(field.helpText)
6667
+ }
6668
+ )
6669
+ ] }),
6670
+ ["select", "radio", "checkbox-group"].includes(fieldType) ? /* @__PURE__ */ jsxs27("label", { children: [
6671
+ "Options",
6672
+ /* @__PURE__ */ jsx30(
6673
+ "textarea",
6674
+ {
6675
+ onChange: (event) => updateField(stepIndex, fieldIndex, {
6676
+ options: fromOptionsText(event.target.value)
6677
+ }),
6678
+ placeholder: "Option one\nOption two",
6679
+ rows: 4,
6680
+ value: toOptionsText(field.options)
6681
+ }
6682
+ )
6683
+ ] }) : null
6684
+ ] }, `edit-field-${stepIndex}-${fieldIndex}`);
6685
+ }),
6686
+ /* @__PURE__ */ jsx30(
6687
+ "button",
6688
+ {
6689
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
6690
+ onClick: () => setEditorState(
6691
+ (current) => current ? {
6692
+ ...current,
6693
+ steps: current.steps.map(
6694
+ (currentStep, index) => index === stepIndex ? { ...currentStep, fields: [...getFields(currentStep), blankField()] } : currentStep
6695
+ )
6696
+ } : current
6697
+ ),
6698
+ type: "button",
6699
+ children: "Add field"
6700
+ }
6701
+ )
6702
+ ] })
6703
+ ] }, `edit-step-${stepIndex}`);
6704
+ }),
6705
+ /* @__PURE__ */ jsx30(
6706
+ "button",
6707
+ {
6708
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
6709
+ onClick: () => setEditorState(
6710
+ (current) => current ? { ...current, steps: [...current.steps, blankStep()] } : current
6711
+ ),
6712
+ type: "button",
6713
+ children: "Add step"
6714
+ }
6715
+ )
6716
+ ] })
6472
6717
  ] }),
6473
- /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: "Edit the public workflow as JSON. The saved payload must remain an array of step objects compatible with the form collection schema." }),
6474
6718
  /* @__PURE__ */ jsx30("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Form" })
6475
6719
  ] })
6476
- ] }),
6477
- /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
6478
- /* @__PURE__ */ jsx30("strong", { children: "Current structure payload" }),
6479
- /* @__PURE__ */ jsx30("span", { children: "Reference snapshot of the form steps that will be written back on save." }),
6480
- /* @__PURE__ */ jsx30("pre", { style: { ...codeStyle, marginTop: "1rem" }, children: editorState.stepsText })
6481
6720
  ] })
6482
6721
  ] }) : null
6483
6722
  ]
@@ -6489,25 +6728,17 @@ function AdminStudioFormDetailView(props) {
6489
6728
  import Link5 from "next/link";
6490
6729
  import { useEffect as useEffect19, useMemo as useMemo15, useState as useState20 } from "react";
6491
6730
  import { Fragment as Fragment6, jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
6492
- var codeStyle2 = {
6493
- background: "color-mix(in srgb, var(--orion-admin-card-bg) 82%, black)",
6494
- border: "1px solid var(--orion-admin-card-border)",
6495
- borderRadius: "var(--orion-admin-radius-sm)",
6496
- color: "var(--orion-admin-text)",
6497
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
6498
- fontSize: "0.86rem",
6499
- lineHeight: 1.55,
6500
- margin: 0,
6501
- maxHeight: "28rem",
6502
- overflow: "auto",
6503
- padding: "0.9rem",
6504
- whiteSpace: "pre-wrap"
6505
- };
6506
6731
  var sectionGridStyle2 = {
6507
6732
  display: "grid",
6508
6733
  gap: "1rem",
6509
6734
  gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
6510
6735
  };
6736
+ var nestedListStyle = {
6737
+ display: "grid",
6738
+ gap: "0.45rem",
6739
+ margin: 0,
6740
+ padding: 0
6741
+ };
6511
6742
  var renderFieldValue = (value) => {
6512
6743
  if (value === null || value === void 0) {
6513
6744
  return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
@@ -6521,7 +6752,26 @@ var renderFieldValue = (value) => {
6521
6752
  if (typeof value === "string") {
6522
6753
  return value.trim().length > 0 ? value : /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
6523
6754
  }
6524
- return /* @__PURE__ */ jsx31("pre", { style: codeStyle2, children: JSON.stringify(value, null, 2) });
6755
+ if (Array.isArray(value)) {
6756
+ const entries = value.filter((entry) => entry !== null && entry !== void 0 && entry !== "");
6757
+ if (entries.length === 0) {
6758
+ return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
6759
+ }
6760
+ return /* @__PURE__ */ jsx31("ul", { style: nestedListStyle, children: entries.map((entry, index) => /* @__PURE__ */ jsx31("li", { children: renderFieldValue(entry) }, index)) });
6761
+ }
6762
+ if (typeof value === "object") {
6763
+ const entries = Object.entries(value).filter(
6764
+ ([, entryValue]) => entryValue !== null && entryValue !== void 0 && entryValue !== ""
6765
+ );
6766
+ if (entries.length === 0) {
6767
+ return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
6768
+ }
6769
+ return /* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.65rem" }, children: entries.map(([key, entryValue]) => /* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
6770
+ /* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: humanizeKey2(key) }),
6771
+ /* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: renderFieldValue(entryValue) })
6772
+ ] }, key)) });
6773
+ }
6774
+ return String(value);
6525
6775
  };
6526
6776
  function getSubmissionIDFromPathname(pathname) {
6527
6777
  return getIDFromPathname(pathname, "/forms/submissions/");
@@ -6673,31 +6923,24 @@ function AdminStudioFormSubmissionView(props) {
6673
6923
  /* @__PURE__ */ jsxs28("article", { className: "orion-admin-overview-stat", children: [
6674
6924
  /* @__PURE__ */ jsx31("span", { className: "orion-admin-overview-stat-label", children: "Highlighted answers" }),
6675
6925
  /* @__PURE__ */ jsx31("strong", { children: previewFields.length }),
6676
- /* @__PURE__ */ jsx31("p", { children: "Readable answer previews surfaced from the structured payload." })
6926
+ /* @__PURE__ */ jsx31("p", { children: "Readable answer previews from this response." })
6677
6927
  ] })
6678
6928
  ] }),
6679
6929
  /* @__PURE__ */ jsxs28("div", { style: sectionGridStyle2, children: [
6680
- /* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: "1rem" }, children: [
6681
- /* @__PURE__ */ jsxs28("div", { className: "orion-admin-card", children: [
6682
- /* @__PURE__ */ jsx31("strong", { children: "Response details" }),
6683
- /* @__PURE__ */ jsx31("span", { children: "Formatted answers using the current form field labels when available." }),
6684
- /* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ jsxs28("div", { className: "orion-admin-form", children: [
6685
- /* @__PURE__ */ jsxs28("div", { children: [
6686
- /* @__PURE__ */ jsx31("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
6687
- /* @__PURE__ */ jsx31("div", { className: "orion-admin-list-meta", children: key })
6688
- ] }),
6689
- /* @__PURE__ */ jsx31("div", { children: renderFieldValue(value) })
6690
- ] }, key)) : /* @__PURE__ */ jsxs28("div", { className: "orion-admin-empty-state", children: [
6691
- /* @__PURE__ */ jsx31("strong", { children: "No response payload" }),
6692
- /* @__PURE__ */ jsx31("span", { children: "This submission does not contain a structured data object." })
6693
- ] }) })
6694
- ] }),
6695
- /* @__PURE__ */ jsxs28("div", { className: "orion-admin-card", children: [
6696
- /* @__PURE__ */ jsx31("strong", { children: "Raw payload" }),
6697
- /* @__PURE__ */ jsx31("span", { children: "Verbatim submission data for troubleshooting or export checks." }),
6698
- /* @__PURE__ */ jsx31("pre", { style: { ...codeStyle2, marginTop: "1rem" }, children: JSON.stringify(doc.data ?? {}, null, 2) })
6699
- ] })
6700
- ] }),
6930
+ /* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "1rem" }, children: /* @__PURE__ */ jsxs28("div", { className: "orion-admin-card", children: [
6931
+ /* @__PURE__ */ jsx31("strong", { children: "Response details" }),
6932
+ /* @__PURE__ */ jsx31("span", { children: "Formatted answers using the current form field labels when available." }),
6933
+ /* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ jsxs28("div", { className: "orion-admin-form", children: [
6934
+ /* @__PURE__ */ jsxs28("div", { children: [
6935
+ /* @__PURE__ */ jsx31("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
6936
+ /* @__PURE__ */ jsx31("div", { className: "orion-admin-list-meta", children: key })
6937
+ ] }),
6938
+ /* @__PURE__ */ jsx31("div", { children: renderFieldValue(value) })
6939
+ ] }, key)) : /* @__PURE__ */ jsxs28("div", { className: "orion-admin-empty-state", children: [
6940
+ /* @__PURE__ */ jsx31("strong", { children: "No answers available" }),
6941
+ /* @__PURE__ */ jsx31("span", { children: "This submission does not contain visible response details." })
6942
+ ] }) })
6943
+ ] }) }),
6701
6944
  /* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: "1rem" }, children: [
6702
6945
  /* @__PURE__ */ jsxs28("div", { className: "orion-admin-card orion-admin-meta-table", children: [
6703
6946
  /* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-studio",
3
- "version": "0.6.0-beta.25",
3
+ "version": "0.6.0-beta.26",
4
4
  "description": "Base CMS, builder, and custom admin toolkit for Orion Studios websites",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",