npm.io
2.2.3 • Published 2 weeks ago

@portabletext/schema

Licence
MIT
Version
2.2.3
Deps
0
Size
46 kB
Vulns
0
Weekly
0
Stars
264

@portabletext/schema

A TypeScript library for defining and compiling Portable Text schemas with full type safety and editor support.

Installation

npm install @portabletext/schema

Usage

Define a schema
import {defineSchema} from '@portabletext/schema'

const schemaDefinition = defineSchema({
  styles: [{name: 'normal'}, {name: 'h1'}, {name: 'h2'}, {name: 'blockquote'}],
  decorators: [{name: 'strong'}, {name: 'em'}],
  annotations: [{name: 'link'}],
  lists: [{name: 'bullet'}, {name: 'numbered'}],
})
Compile schema
import {compileSchema} from '@portabletext/schema'

const schema = compileSchema(schemaDefinition)

Containers and sub-schemas

A block object can act as a container: one of its fields is an array whose of includes a {type: 'block'} member, which declares the text sub-schema allowed inside it. This is how a code block, callout, or table cell restricts what can be typed within it.

const schemaDefinition = defineSchema({
  decorators: [{name: 'strong'}, {name: 'em'}, {name: 'code'}],
  styles: [{name: 'normal'}, {name: 'h1'}],
  blockObjects: [
    {
      name: 'code-block',
      fields: [
        {
          name: 'lines',
          type: 'array',
          of: [
            // A code line: a `code` style only, and no decorators.
            {type: 'block', styles: [{name: 'code'}], decorators: []},
          ],
        },
      ],
    },
  ],
})

Use getSubSchema to resolve what is allowed at a position inside a container. It returns a Schema you can treat like any top-level one:

import {compileSchema, getSubSchema} from '@portabletext/schema'

const schema = compileSchema(schemaDefinition)
const codeBlock = schema.blockObjects.find((type) => type.name === 'code-block')
const lines = codeBlock.fields.find((field) => field.name === 'lines')

const subSchema = getSubSchema(schema, lines.of)
// subSchema.decorators === []                 (the code line forbids decorators)
// subSchema.styles     === [{name: 'code', ...}] (only the `code` style)
How a nested block overrides and inherits

Each of styles, decorators, annotations, lists, and inlineObjects resolves independently:

  • Declared overrides for that property.
  • Declared empty ([]) overrides to nothing, e.g. decorators: [] forbids every decorator inside the container.
  • Absent inherits from the nearest enclosing container that declares a block, or the root when none does.

There is no merging: a property is either declared here or taken whole from a single source. An absent property resolves against the nearest enclosing container whose block declares it, so a block nested inside a container that restricts its own text inherits that restriction rather than the document root. It falls back to the root only when no enclosing container declares a block of its own (e.g. structural tablerowcell wrappers, where the cell's text inherits the document). A nested block never blends multiple ancestors; it takes exactly one inherited value. When the of has no {type: 'block'} member at all, the container allows objects only, with no text formatting.

Keywords