Composition / foldkit-composition

Sixty seconds

ts
import { Schema } from 'effect'
import { Block, Catalog, Composition, Content, Region } from 'foldkit-composition'

const Heading = Block.define('Heading', {
  Props: Schema.Struct({ text: Schema.String, level: Schema.Literals([1, 2, 3]) }),
  provides: [Content.Flow],
})

const Section = Block.define('Section', {
  Props: Schema.Struct({ tone: Schema.Literals(['plain', 'accent']) }),
  regions: { body: Region.many({ accepts: [Content.Flow] }) },
  provides: [Content.Section],
})

const Site = Catalog.make({ blocks: [Heading, Section], roots: [Content.Section] })

const page = Schema.decodeUnknownSync(Composition.Document)({
  format: 1,
  roots: ['intro'],
  nodes: {
    intro: { block: 'Section', props: { tone: 'plain' }, regions: { body: ['title'] } },
    title: { block: 'Heading', props: { text: 'Hello', level: 1 }, regions: {} },
  },
})

Composition.validate(Site, page) // []
Composition.describe(Site, page)
// Section intro {"tone":"plain"}
//   body:
//     Heading title {"level":1,"text":"Hello"}
  • Block.define and Catalog.make describe; nothing runs. A Catalog with two Blocks of one name, a Region that accepts nothing, or a Block that provides nothing throws when it is made.
  • Composition.Document is a Schema: the Document is plain JSON, stored in a column or a field like any other value.
  • validate returns what is wrong, each finding with a code, the node, a path and a sentence. It never changes the Document.