Skip to content

Commit

Permalink
refactor(form-builder): inject ArrayFunctions as prop instead of impo…
Browse files Browse the repository at this point in the history
…rting
  • Loading branch information
bjoerge committed Apr 28, 2021
1 parent a391a1c commit 828fc45
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import React from 'react'
import {map} from 'rxjs/operators'
import {Subscription} from 'rxjs'
import {randomKey, resolveTypeName} from '@sanity/util/content'
import {ArrayFunctions} from '../../../legacyParts'
import {insert, PatchEvent, set, setIfMissing, unset} from '../../../PatchEvent'
import {ResolvedUploader, Uploader, UploadEvent} from '../../../sanity/uploads/types'
import {Alert} from '../../../components/Alert'
import {Details} from '../../../components/Details'
import {Item, List} from '../common/list'
import {EMPTY_ARRAY} from '../../../utils/empty'
import ArrayFunctions from '../common/ArrayFunctions'
import {ArrayItem} from './item'
import {ArrayMember} from './types'
import {uploadTarget} from './uploadTarget/uploadTarget'
Expand All @@ -34,7 +34,7 @@ function createProtoValue(type: SchemaType): ArrayMember {
return type.name === 'object' ? {_key} : {_type: type.name, _key}
}

export type Props = {
export interface Props {
type: ArraySchemaType
value: ArrayMember[]
compareValue: ArrayMember[]
Expand All @@ -47,7 +47,8 @@ export type Props = {
readOnly: boolean
directUploads?: boolean
filterField: () => any
resolveUploader?: (type: SchemaType, file: File) => Uploader
ArrayFunctionsImpl: typeof ArrayFunctions
resolveUploader?: (type: SchemaType, file: File) => Uploader | null
presence: FormFieldPresence[]
}

Expand Down Expand Up @@ -177,7 +178,7 @@ export class ArrayInput extends React.Component<Props> {
type: memberType,
uploader: resolveUploader(memberType, file),
}))
.filter((member) => member.uploader)
.filter((member) => member.uploader) as ResolvedUploader[]
}

handleFixMissingKeys = () => {
Expand Down Expand Up @@ -233,6 +234,7 @@ export class ArrayInput extends React.Component<Props> {
compareValue,
filterField,
directUploads,
ArrayFunctionsImpl,
} = this.props

const hasNonObjectValues = (value || []).some((item) => !isPlainObject(item))
Expand Down Expand Up @@ -367,13 +369,13 @@ export class ArrayInput extends React.Component<Props> {
</List>
)}

<ArrayFunctions
<ArrayFunctionsImpl
type={type}
value={value}
readOnly={readOnly}
onAppendItem={this.handleAppend}
onPrependItem={this.handlePrepend}
onFocusItem={onFocus}
onFocusItem={this.handleFocusItem}
onCreateValue={createProtoValue}
onChange={onChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,45 @@ import {FormFieldPresence} from '@sanity/base/presence'
import {resolveTypeName} from '@sanity/util/content'
import {PatchEvent, set, unset} from '../../../PatchEvent'
import {Item, List} from '../common/list'
import {ArrayFunctions} from '../../../legacyParts'
import ArrayFunctions from '../common/ArrayFunctions'
import getEmptyValue from './getEmptyValue'
import {ItemRow} from './ItemRow'

type Primitive = string | number | boolean

const NO_MARKERS: Marker[] = []

function move(arr: Primitive[], from: number, to: number): Primitive[] {
function move<T>(arr: T[], from: number, to: number): T[] {
const copy = arr.slice()
const val = copy[from]
copy.splice(from, 1)
copy.splice(to, 0, val)
return copy
}

function insertAt(arr: Primitive[], index: number, item: Primitive): Primitive[] {
function insertAt<T>(arr: T[], index: number, item: T): T[] {
const copy = arr.slice()
copy.splice(index + 1, 0, item)
return copy
}

type Props = {
type?: ArraySchemaType<Primitive>
export interface Props {
type: ArraySchemaType<Primitive>
value: Primitive[]
compareValue?: Primitive[]
level: number
onChange: (event: PatchEvent) => void
onFocus: (path: Path) => void
onBlur: () => void
focusPath: Path
ArrayFunctionsImpl: typeof ArrayFunctions
readOnly: boolean | null
markers: Marker[]
presence: FormFieldPresence[]
}
type Focusable = {focus: () => void}

export default class ArrayOfPrimitivesInput extends React.PureComponent<Props> {
export class ArrayOfPrimitivesInput extends React.PureComponent<Props> {
_element: Focusable | null = null
_lastAddedIndex = -1

Expand Down Expand Up @@ -130,7 +131,7 @@ export default class ArrayOfPrimitivesInput extends React.PureComponent<Props> {
}
}

handleFocusItem = (index: number) => {
handleFocusItem = (item: Primitive, index: number) => {
this.props.onFocus([index])
}

Expand All @@ -146,6 +147,7 @@ export default class ArrayOfPrimitivesInput extends React.PureComponent<Props> {
presence,
compareValue,
focusPath,
ArrayFunctionsImpl,
onBlur,
} = this.props

Expand Down Expand Up @@ -199,7 +201,7 @@ export default class ArrayOfPrimitivesInput extends React.PureComponent<Props> {
</List>
)}

<ArrayFunctions
<ArrayFunctionsImpl<Primitive>
type={type}
value={value}
readOnly={readOnly}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {SchemaType} from '@sanity/types'

export default function getEmptyValue(type: SchemaType) {
export default function getEmptyValue(type: SchemaType): number | string | boolean {
switch (type.jsonType) {
case 'string': {
return ''
Expand All @@ -12,6 +12,6 @@ export default function getEmptyValue(type: SchemaType) {
return false
}
default:
return undefined
throw new Error(`Unable to create value from type "${type.jsonType}"`)
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export {default} from './ArrayOfPrimitivesInput'
export * from './ArrayOfPrimitivesInput'
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import {ArraySchemaType, isReferenceSchemaType, SchemaType} from '@sanity/types'
import {ArraySchemaType, isReferenceSchemaType} from '@sanity/types'
import {AddIcon} from '@sanity/icons'
import React from 'react'
import React, {ReactNode} from 'react'
import {Button, Grid, Menu, MenuButton, MenuItem} from '@sanity/ui'
import {useId} from '@reach/auto-id'
import PatchEvent from '../../../PatchEvent'
import {ArrayMember} from '../ArrayOfObjectsInput/types'

// These are the props any implementation of the ArrayFunctions part will receive
interface ArrayFunctionsProps {
/* eslint-disable react/no-unused-prop-types */
export interface ArrayFunctionsProps<SchemaType extends ArraySchemaType, MemberType> {
className?: string
type: ArraySchemaType
children: Node | null
value: ArrayMember[]
type: SchemaType
children?: ReactNode
value?: MemberType[]
readOnly: boolean | null
onAppendItem: (itemValue: ArrayMember) => void
onPrependItem: (itemValue: ArrayMember) => void
onFocusItem: (item: ArrayMember) => void
onCreateValue: (type: SchemaType) => ArrayMember
onAppendItem: (itemValue: MemberType) => void
onPrependItem: (itemValue: MemberType) => void
onFocusItem: (item: MemberType, index: number) => void
onCreateValue: (type: SchemaType) => MemberType
onChange: (event: PatchEvent) => void
/* eslint-enable react/no-unused-prop-types */
}

export default function ArrayFunctions(props: ArrayFunctionsProps) {
export default function ArrayFunctions<MemberType>(
props: ArrayFunctionsProps<ArraySchemaType, MemberType>
) {
const {type, readOnly, children, onCreateValue, onAppendItem} = props
const menuButtonId = useId()

Expand Down
2 changes: 0 additions & 2 deletions packages/@sanity/form-builder/src/legacyParts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// legacy plugin parts - e.g. parts ids that are documented as overridable
import ArrayFunctions from 'part:@sanity/form-builder/input/array/functions'
import BooleanInput from 'part:@sanity/form-builder/input/boolean?'
import DateTimeInput from 'part:@sanity/form-builder/input/datetime?'
import EmailInput from 'part:@sanity/form-builder/input/email?'
Expand Down Expand Up @@ -42,7 +41,6 @@ import ProgressCirclePart from 'part:@sanity/components/progress/circle'
import defaultAssetSources from 'all:part:@sanity/form-builder/input/image/asset-source'

export {
ArrayFunctions,
BooleanInput,
DateTimeInput,
EmailInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import TextInput from '../../inputs/TextInput'
import UrlInput from '../../inputs/UrlInput'
import SlugInput from '../../inputs/Slug/SlugInput'

import SanityArrayInput from '../inputs/SanityArrayInput'
import {SanityArrayInput} from '../inputs/SanityArrayInput'
import Image from '../inputs/SanityImageInput'
import File from '../inputs/SanityFileInput'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import {ArraySchemaType} from '@sanity/types'
import * as is from '../../utils/is'
import OptionsArray from '../../inputs/arrays/OptionsArrayInput'
import PortableTextInput from '../../inputs/PortableText/PortableTextInput'
import ArrayOfPrimitivesInput from '../../inputs/arrays/ArrayOfPrimitivesInput'
import {TagsArrayInput} from '../../inputs/TagsArrayInput'
import SanityArrayInput from '../inputs/SanityArrayInput'
import {SanityArrayInput, SanityArrayOfPrimitivesInput} from '../inputs/SanityArrayInput'
import {Props} from '../../inputs/types'

const PRIMITIVES = ['string', 'number', 'boolean']
Expand Down Expand Up @@ -45,7 +44,7 @@ export default function resolveArrayInput(type: ArraySchemaType): ComponentType<
// Special component for array of primitive values
if (isArrayOfPrimitives(type)) {
// @todo: fix typing
return ArrayOfPrimitivesInput as ComponentType<any>
return SanityArrayOfPrimitivesInput as ComponentType<any>
}

// Use Portable Text editor if portable text.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
import React from 'react'
import React, {ForwardedRef, forwardRef} from 'react'
import formBuilderConfig from 'config:@sanity/form-builder'
import ArrayFunctions from 'part:@sanity/form-builder/input/array/functions'
import resolveUploader from '../uploads/resolveUploader'
import ArrayInput, {Props} from '../../inputs/arrays/ArrayOfObjectsInput'
import {
ArrayOfPrimitivesInput,
Props as PrimitiveArrayInputProps,
} from '../../inputs/arrays/ArrayOfPrimitivesInput'

const SUPPORT_DIRECT_UPLOADS = formBuilderConfig?.images?.directUploads

export default class SanityArray extends React.Component<Props> {
input: any
setInput = (input) => {
this.input = input
}
focus() {
this.input.focus()
}
render() {
return (
<ArrayInput
ref={this.setInput}
{...this.props}
resolveUploader={resolveUploader}
directUploads={SUPPORT_DIRECT_UPLOADS}
/>
)
}
}
export const SanityArrayInput = forwardRef(function SanityArrayInput(
props: Props,
ref: ForwardedRef<ArrayInput>
) {
return (
<ArrayInput
{...props}
ref={ref}
resolveUploader={resolveUploader}
ArrayFunctionsImpl={ArrayFunctions}
directUploads={SUPPORT_DIRECT_UPLOADS}
/>
)
})

export const SanityArrayOfPrimitivesInput = forwardRef(function SanityArrayOfPrimitivesInput(
props: Omit<PrimitiveArrayInputProps, 'ArrayFunctionsImpl'>,
ref: ForwardedRef<ArrayOfPrimitivesInput>
) {
return <ArrayOfPrimitivesInput {...props} ArrayFunctionsImpl={ArrayFunctions} ref={ref} />
})
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import {ImageSchemaType, FileSchemaType} from '@sanity/types'
import {SchemaType} from '@sanity/types'
import accept from 'attr-accept'
import * as is from '../../utils/is'
import uploaders from './uploaders'
import {Uploader} from './types'

export default function resolveUploader(
type: ImageSchemaType | FileSchemaType,
file: File
): Uploader | null {
export default function resolveUploader(type: SchemaType, file: File): Uploader | null {
return uploaders.find((uploader) => {
return (
is.type(uploader.type, type) &&
accept(file, uploader.accepts) &&
accept(file, type.options?.accept || '')
accept(file, (type.options as any)?.accept || '')
)
})
}

0 comments on commit 828fc45

Please sign in to comment.