Skip to content

Commit

Permalink
[form-builder] Unset empty object when removing asset (#1647)
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars committed Dec 18, 2019
1 parent b92b6ac commit 63964c7
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 4 deletions.
33 changes: 32 additions & 1 deletion packages/@sanity/form-builder/src/inputs/FileInput/FileInput.tsx
@@ -1,5 +1,6 @@
/* eslint-disable complexity */
import React from 'react'
import PropTypes from 'prop-types'
import Button from 'part:@sanity/components/buttons/default'
import FileInputButton from 'part:@sanity/components/fileinput/button'
import ProgressBar from 'part:@sanity/components/progress/bar'
Expand Down Expand Up @@ -52,7 +53,12 @@ type FileInputState = {
isAdvancedEditOpen: boolean
hasFocus: boolean
}

export default class FileInput extends React.PureComponent<Props, FileInputState> {
static contextTypes = {
getValuePath: PropTypes.func
}

_focusArea: any
uploadSubscription: any
state = {
Expand All @@ -62,7 +68,32 @@ export default class FileInput extends React.PureComponent<Props, FileInputState
hasFocus: false
}
handleRemoveButtonClick = (event: React.SyntheticEvent<any>) => {
this.props.onChange(PatchEvent.from(unset(['asset'])))
const {getValuePath} = this.context
const {value} = this.props
const parentPathSegment = getValuePath().slice(-1)[0]

// String path segment mean an object path, while a number or a
// keyed segment means we're a direct child of an array
const isArrayElement = typeof parentPathSegment !== 'string'

// When removing the file, _type and _key are "meta"-properties and
// are not significant unless other properties are present. Thus, we
// want to remove the entire "container" object if these are the only
// properties present, BUT only if we're not an array element, as
// removing the array element will close the selection dialog. Instead,
// when closing the dialog, the array logic will check for an "empty"
// value and remove it for us
const allKeys = Object.keys(value)
const remainingKeys = allKeys.filter(
key => !['_type', '_key', '_upload', 'asset'].includes(key)
)

const isEmpty = remainingKeys.length === 0
const removeKeys = ['asset']
.concat(allKeys.filter(key => ['_upload'].includes(key)))
.map(key => unset([key]))

this.props.onChange(PatchEvent.from(isEmpty && !isArrayElement ? unset() : removeKeys))
}

clearUploadStatus() {
Expand Down
36 changes: 33 additions & 3 deletions packages/@sanity/form-builder/src/inputs/ImageInput/ImageInput.tsx
Expand Up @@ -4,6 +4,7 @@ import {Observable} from 'rxjs'
import HotspotImage from '@sanity/imagetool/HotspotImage'
import ImageTool from '@sanity/imagetool'
import React from 'react'
import PropTypes from 'prop-types'

// Parts
import assetSources from 'all:part:@sanity/form-builder/input/image/asset-source'
Expand Down Expand Up @@ -70,7 +71,7 @@ export interface Value {

export type Props = {
value?: Value
document?: Value,
document?: Value
type: Type
level: number
onChange: (arg0: PatchEvent) => void
Expand Down Expand Up @@ -100,6 +101,10 @@ type ImageInputState = {
const globalAssetSources = userDefinedAssetSources ? userDefinedAssetSources : assetSources

export default class ImageInput extends React.PureComponent<Props, ImageInputState> {
static contextTypes = {
getValuePath: PropTypes.func
}

_focusArea: any
uploadSubscription: any
state = {
Expand Down Expand Up @@ -217,7 +222,32 @@ export default class ImageInput extends React.PureComponent<Props, ImageInputSta
}

handleRemoveButtonClick = (event: React.SyntheticEvent<any>) => {
this.props.onChange(PatchEvent.from(unset(['asset'])))
const {getValuePath} = this.context
const {value} = this.props
const parentPathSegment = getValuePath().slice(-1)[0]

// String path segment mean an object path, while a number or a
// keyed segment means we're a direct child of an array
const isArrayElement = typeof parentPathSegment !== 'string'

// When removing the image, we should also remove any crop and hotspot
// _type and _key are "meta"-properties and are not significant unless
// other properties are present. Thus, we want to remove the entire
// "container" object if these are the only properties present, BUT
// only if we're not an array element, as removing the array element
// will close the selection dialog. Instead, when closing the dialog,
// the array logic will check for an "empty" value and remove it for us
const allKeys = Object.keys(value)
const remainingKeys = allKeys.filter(
key => !['_type', '_key', '_upload', 'asset', 'crop', 'hotspot'].includes(key)
)

const isEmpty = remainingKeys.length === 0
const removeKeys = ['asset']
.concat(allKeys.filter(key => ['crop', 'hotspot', '_upload'].includes(key)))
.map(key => unset([key]))

this.props.onChange(PatchEvent.from(isEmpty && !isArrayElement ? unset() : removeKeys))
}

handleFieldChange = (event: PatchEvent, field: FieldT) => {
Expand Down Expand Up @@ -584,4 +614,4 @@ export default class ImageInput extends React.PureComponent<Props, ImageInputSta
</FieldSetComponent>
)
}
}
}

0 comments on commit 63964c7

Please sign in to comment.