@sanity/schema
Version:
166 lines (143 loc) • 3.95 kB
text/typescript
import {pick} from 'lodash'
import createPreviewGetter from '../../preview/createPreviewGetter'
import {OWN_PROPS_NAME} from '../constants'
import {hiddenGetter, lazyGetter} from '../utils'
import {
BLOCK_STYLES,
DEFAULT_BLOCK_STYLES,
DEFAULT_DECORATORS,
DEFAULT_LINK_ANNOTATION,
DEFAULT_LIST_TYPES,
DEFAULT_MARKS_FIELD,
DEFAULT_TEXT_FIELD,
} from './defaults'
const INHERITED_FIELDS = [
'type',
'name',
'title',
'jsonType',
'description',
'options',
'fieldsets',
'icon',
]
const BLOCK_CORE = {
name: 'block',
title: 'Block',
type: null,
jsonType: 'object',
}
const DEFAULT_OPTIONS = {}
export const BlockType = {
get() {
return BLOCK_CORE
},
extend(subTypeDef: any, extendMember: any) {
const options = {...(subTypeDef.options || DEFAULT_OPTIONS)}
const {marks, styles, lists, of, ...rest} = subTypeDef
const childrenField = createChildrenField(marks, of)
const styleField = createStyleField(styles)
const listItemField = createListItemField(lists)
const markDefsField = {
name: 'markDefs',
title: 'Mark definitions',
type: 'array',
of: marks?.annotations || DEFAULT_ANNOTATIONS,
}
const levelField = {
name: 'level',
title: 'Indentation',
type: 'number',
}
// NOTE: if you update this (EVEN THE ORDER OF FIELDS) you _NEED TO_ also
// update `BlockSchemaType`, `isBlockSchemaType` and similar in `@sanity/types`
const fields = [childrenField, styleField, listItemField, markDefsField, levelField].concat(
subTypeDef.fields || [],
)
const ownProps = {...rest, options}
const parsed = Object.assign(pick(BLOCK_CORE, INHERITED_FIELDS), ownProps, {
type: BLOCK_CORE,
})
lazyGetter(parsed, 'fields', () => {
return fields.map((fieldDef) => {
const {name, ...type} = fieldDef
return {
name: name,
type: extendMember(type),
}
})
})
lazyGetter(parsed, 'preview', createPreviewGetter(subTypeDef))
lazyGetter(
parsed,
OWN_PROPS_NAME,
() => ({
...ownProps,
fields: parsed.fields,
preview: parsed.preview,
}),
{enumerable: false, writable: false},
)
return subtype(parsed)
function subtype(parent: any) {
return {
get() {
return parent
},
extend: (extensionDef: any) => {
if (extensionDef.fields) {
throw new Error('Cannot override `fields` of subtypes of "block"')
}
const subOwnProps = pick(extensionDef, INHERITED_FIELDS)
const current = Object.assign({}, parent, subOwnProps, {
type: parent,
})
hiddenGetter(current, OWN_PROPS_NAME, subOwnProps)
return subtype(current)
},
}
}
},
}
function ensureNormalStyle(styles: any) {
return styles.some((style: any) => style.value === 'normal')
? styles
: [BLOCK_STYLES.normal, ...styles]
}
function createStyleField(styles: any) {
return {
name: 'style',
title: 'Style',
type: 'string',
options: {
list: ensureNormalStyle(styles || DEFAULT_BLOCK_STYLES),
},
}
}
function createListItemField(lists: any) {
return {
name: 'listItem',
title: 'List type',
type: 'string',
options: {
list: lists || DEFAULT_LIST_TYPES,
},
}
}
const DEFAULT_ANNOTATIONS = [DEFAULT_LINK_ANNOTATION]
function createChildrenField(marks: any, of = []) {
return {
name: 'children',
title: 'Content',
type: 'array',
of: [
{
type: 'span',
fields: [DEFAULT_TEXT_FIELD, DEFAULT_MARKS_FIELD],
annotations: marks && marks.annotations ? marks.annotations : DEFAULT_ANNOTATIONS,
decorators: marks && marks.decorators ? marks.decorators : DEFAULT_DECORATORS,
},
...of.filter((memberType: any) => memberType.type !== 'span'),
],
}
}