UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

166 lines (142 loc) 5.34 kB
import {isKeySegment, type Path} from '@sanity/types' import {castArray} from 'lodash' import {isMemberArrayOfObjects, isMemberObject} from '../../members/object/fields/asserters' import {ALL_FIELDS_GROUP} from '../constants' import { type ArrayOfObjectsFormNode, type ArrayOfObjectsItemMember, type BaseFormNode, type FieldMember, type FieldSetMember, type ObjectFormNode, type ObjectMember, } from '../types' import {isArrayOfObjectsFormNode, isObjectFormNode} from '../types/asserters' /** @internal */ export interface ExpandPathOperation { type: 'expandPath' path: Path } /** @internal */ export interface ExpandFieldSetOperation { type: 'expandFieldSet' path: Path } /** @internal */ export interface SetActiveGroupOperation { type: 'setSelectedGroup' path: Path groupName: string } /** @internal */ export type ExpandOperation = | ExpandPathOperation | ExpandFieldSetOperation | SetActiveGroupOperation function hasAllMembers<T extends BaseFormNode>(value: T): value is HasAllMembers<T> { return '_allMembers' in value && Array.isArray(value._allMembers) } /** * This takes a form state and returns a list of operations required to open a node at a particular path * @param node - The base form node (i.e. the form state node for the _document_) * @param path - The path to open * * @internal */ export function getExpandOperations(node: BaseFormNode, path: Path): ExpandOperation[] { return [ // make sure to expand all intermediate paths ...path.map((p, i): ExpandPathOperation => ({type: 'expandPath', path: path.slice(0, i + 1)})), // make sure to expand all fieldsets and selects the groups that includes the intermediate nodes ...getFieldsetAndFieldGroupOperations(node, path), ] } function getFieldsetAndFieldGroupOperations(node: BaseFormNode, path: Path) { if (path.length === 0) { return [] } if (isObjectFormNode(node) && hasAllMembers(node)) { return getObjectFieldsetAndFieldGroupOperations(node, path) } if (isArrayOfObjectsFormNode(node)) { return getArrayFieldsetAndFieldGroupOperations(node, path) } return [] } type HasAllMembers<T> = T & {_allMembers: ObjectMember[]} function getObjectFieldsetAndFieldGroupOperations( node: HasAllMembers<ObjectFormNode>, path: Path, ): (ExpandFieldSetOperation | SetActiveGroupOperation)[] { if (path.length === 0) { return [] } // extract the field name for the current level we're looking at const [fieldName, ...tail] = path const fieldsetMember = node._allMembers.find( (member): member is FieldSetMember => member.kind === 'fieldSet' && member.fieldSet.members.some( (field): field is FieldMember => field.kind === 'field' && field.name === fieldName, ), ) // if we found the field in a fieldset we need to recurse into this fieldset's members, otherwise we can use the node's members const members = fieldsetMember ? fieldsetMember.fieldSet.members : // Note: we need to use the internal `_allMembers` array here instead of members since hidden/collapsed members are omitted from members node._allMembers // look for the field inside the members array const fieldMember = members.find( (member): member is FieldMember => member !== null && member.kind === 'field' && member.name === fieldName, ) // Group handling const schemaField = node.schemaType.fields.find((field) => field.name === fieldName) const selectedGroupName = node.groups.find((group) => group.selected)?.name const defaultGroupName = (node.schemaType.groups || []).find((group) => group.default)?.name const inSelectedGroup = selectedGroupName && (selectedGroupName === ALL_FIELDS_GROUP.name || (schemaField && castArray(schemaField.group).includes(selectedGroupName))) const ops: (ExpandFieldSetOperation | SetActiveGroupOperation)[] = [] if (!inSelectedGroup) { ops.push({ type: 'setSelectedGroup', path: node.path, groupName: defaultGroupName || ALL_FIELDS_GROUP.name, }) } if (fieldsetMember) { // the field is inside a fieldset, make sure we expand it too ops.push({type: 'expandFieldSet', path: fieldsetMember.fieldSet.path}) } if (fieldMember && hasAllMembers(fieldMember.field)) { if (isMemberArrayOfObjects(fieldMember)) { ops.push(...getArrayFieldsetAndFieldGroupOperations(fieldMember.field, tail)) } else if (isMemberObject(fieldMember)) { ops.push(...getObjectFieldsetAndFieldGroupOperations(fieldMember.field, tail)) } } return ops } function getArrayFieldsetAndFieldGroupOperations( state: ArrayOfObjectsFormNode, path: Path, ): (ExpandFieldSetOperation | SetActiveGroupOperation)[] { if (path.length === 0) { return [] } // start at the root and make sure all groups/paths are expanded/activated along the way const [segment, ...rest] = path if (!isKeySegment(segment)) { throw new Error('Expected path segment to be an object with a _key property') } const foundMember = state.members.find( (member): member is ArrayOfObjectsItemMember => member.key === segment._key, ) if (!foundMember) { // tried to open a member that does not exist in the form state - it's likely hidden return [] } return getFieldsetAndFieldGroupOperations(foundMember.item, rest) }