Discussion on displaying file URLs for a custom component in a Sanity.io project

8 replies
Last updated: Aug 22, 2021
Hi, I have written a custom component to display a file url below the file upload field. So far, it correctly displays the url, but only for the first element of the array (works if I reorder the elements as well). How could I make sure I get the correct values for each element of the array? (Code and screenshots are attached below)
Aug 21, 2021, 11:44 AM
FontUrl.js component code:
import React from 'react'
import { withDocument } from 'part:@sanity/form-builder'

// build a file url
export function fileUrl(reference) {
  const project = {
    projectId: process.env.SANITY_STUDIO_API_PROJECT_ID,
    dataset: process.env.SANITY_STUDIO_API_DATASET || 'production'
  }
  
  const referenceArray = reference.split('-')
  const asset = {
    assetId: referenceArray[1],
    extension: referenceArray[2]
  }

  return `<https://cdn.sanity.io/files/${project.projectId}/${project.dataset}/${asset.assetId}.${asset.extension}>`
}

const FontUrl = React.forwardRef((props) => {
  for(let i=0; i<props.document.fontFiles.length; i++) {
    const reference = props.document.fontFiles[i].asset._ref

    return (
      <p>{fileUrl(reference)}</p>
    )
  }
})

export default withDocument(FontUrl)
Aug 21, 2021, 11:47 AM
A snippet of the schema code:
{
      name: 'fontFiles',
      title: 'Font files',
      description: 'Upload font files, add below with @font-face. Accepted formats: .woff, .woff2',
      type: 'array',
      of: [
        {
          type: 'file',
          options: {
            accept: '.woff2, .woff',
          },
          fields: [{
            name: 'fontUrl',
            title: 'Font URL',
            description: 'Use in CSS @font-face',
            type: 'url',
            // below adding a component
            inputComponent: FontUrl,
            readOnly: true,
            options: {
              isHighlighted: true,
            }
          }],
        }
      ]
    },
Aug 21, 2021, 11:50 AM
Screenshots (sorry, components as well as other details are not finished yet)
Aug 21, 2021, 11:59 AM
Hi Paul, do you want
<FontUrl>
to display the urls of all uploaded fonts? If so, you should change the code so FontUrl doesn’t return from within a loop (will only loop once).
You could do something like this:


const FontUrl = React.forwardRef((props) => {
  const { fontFiles } = props.document
  return (
    <>
      <p>{fontFiles.map(fontFile => fileUrl(fontFile.asset._ref)})}</p>
    </>
  )
})
Aug 21, 2021, 3:40 PM
It's slightly different. I wanted to display only the url for the selected/expanded field. You can see on the screenshots that currently it displays the the url of the first font (.woff2) in both cases. I wonder if it would be possible to display .woff2 for the first one and .woff for the second one (with other data being different as well, of course)
Aug 21, 2021, 4:12 PM
In that case you’ll need to import
withValuePath
as well, as well, it will show you which array the current custom field belongs to, so you can get the file.

import { withDocument, withValuePath } from 'part:@sanity/form-builder'

export const FontUrl = withValuePath(withDocument(({ document, getValuePath }) => {
  console.log(document) // { _id: ... }
  console.log(getValuePath()) // ["content", { _key: ... }]
}))

Aug 21, 2021, 4:39 PM
Finally finished it! I think it turned out quite nice.
const FontUrl = React.forwardRef((props, ref) => {
  const matchingUrl = props.document.fontFiles.find(fontFile => fontFile._key === props.getValuePath()[1]._key);

  return (
    <p>{matchingUrl.asset ? fileUrl(matchingUrl.asset._ref) : null}</p>
  )
})

export default withValuePath(withDocument(FontUrl))
Thank you so much for helping me out!
Aug 22, 2021, 5:35 AM
Congrats Paul! If you'd like to style the url to look the same as other fields in the studio, check out sanity ui! https://www.sanity.io/ui/docs
Aug 22, 2021, 5:39 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?