Skip to content

feat(editor): support arrays of relations - #549

Open
nadaamd wants to merge 2 commits into
nuxt-content:mainfrom
nadaamd:feat/relation-input-array
Open

feat(editor): support arrays of relations#549
nadaamd wants to merge 2 commits into
nuxt-content:mainfrom
nadaamd:feat/relation-input-array

Conversation

@nadaamd

@nadaamd nadaamd commented Aug 24, 2026

Copy link
Copy Markdown

Extends the relation input to arrays, so z.array(z.string()) gets one picker
per entry instead of free-text badges.

Important

Stacked on #548. This branch contains that PR's commit as its base, so the
diff below shows both. Review only the second commit, 5afef9c — or the
compare against that branch.
Merge #548 first and this will shrink to the array change alone.

authors: property(z.array(z.string())).editor({
  input: 'relation',
  relation: { collection: 'authors', labelField: 'name' },
})

Refs #219, and #307 which was closed in favour of it — that one asked for this
array shape specifically.

Two bugs in the array path

A relation set on an array applies to its items — the editor option sits on
the array, while the value holding the reference is each entry. Neither array
path in buildFormTreeFromSchema handled that:

  1. The main path dropped the option. The array branch hardcodes
    type: 'array' and builds arrayItemForm from def.items, which never sees
    the parent's $content.editor. So the field fell back to string badges.

  2. Past the object depth limit the array type was lost entirely. There
    type comes from editor.input, so an array with input: 'relation' became
    a relation item and type === 'array' went false — the field ended up with
    no arrayItemForm to render at all.

Both now keep the array and push the relation down to the item form, via one
shared applyRelationToArrayItem helper.

Scope

Only string items are converted. An array of objects or numbers keeps exactly
the form it had before, so this cannot change how an existing schema renders.

The propagation is deliberately limited to relation rather than any
editor.input. Generalising it would send input: 'media' on an array to
InputArray's unsupportedType branch, which is a regression for anyone
relying on today's behaviour — worth doing, but as its own change with its own
per-type branch.

Relation to #518

#518 fixes the neighbouring case (arrays of enums) and touches the same file. No
conflict expected: it needs no form.ts change, because for z.array(z.enum())
the enum sits on def.items and already reaches the item form. This branch adds
its own v-else-if in the same spot and follows #518's row layout — input plus
reorder and delete buttons — so whichever lands first, the other is a trivial
rebase. Happy to rebase on top of it if you would rather take that one first.

Test plan

  • src/app/test/unit/utils/form.test.ts — 3 new cases: array of relations,
    the deep-nesting path, and a guard that non-string items are left alone.
    The first two fail without this change (expected 'relation' to be 'array'
    on the deep path), so they are regression tests rather than restatements.
  • pnpm verify passes: lint clean, nuxt typecheck and
    vue-tsc -p src/app/tsconfig.app.json clean, 416 tests green, pnpm test:types
    clean.
  • Verified against real build output: with reviewers added to the docus
    playground, the generated Draft-07 in .nuxt/content/preview.mjs carries
    $content.editor.relation on the array definition, which is what the form
    builder consumes.
  • playground/docus now has both shapes on the docs collection — author
    (single) from feat(editor): add relation input to reference another collection #548 and reviewers (array) here — both pointing at the
    existing authors data collection.

nadaamd and others added 2 commits August 24, 2026 14:47
Renders a searchable picker for string fields that reference a document of
another collection, instead of leaving editors to type an identifier by hand.

Options are read from the existing host bridge (`document.db.list()` filtered
by `collection.getByFsPath()`), so no new route is needed. The field keeps
storing a plain string: file format and content queries are unaffected, the
value stays editable by hand, and a value matching no document is flagged but
never rewritten.

Refs nuxt-content#219

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A relation set on an array applies to its items: the editor option sits on the
array while the value holding the reference is each entry. The array branch of
`buildFormTreeFromSchema` dropped that option, so `z.array(z.string())` fell
back to free-text badges.

Past the object depth limit the editor input also replaced the array type
itself, leaving the field with no item form to render. Both paths now keep the
array and push the relation down to its item form, and `InputArray` renders one
picker per entry alongside the usual reorder and delete controls.

Only string items are converted, so an array of objects or numbers keeps the
form it had before.

Refs nuxt-content#219

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@nadaamd is attempting to deploy a commit to the Nuxt Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant