[RFC]: Nesting Block #2049
Replies: 3 comments
|
I really like this, and I think it would unlock a lot of use cases. You have identified the biggest potential issue though: the editor. I think this is worth approving for PR, but I think the first steps than anybody should take are some experiments with the editor. |
|
https://github.com/louisescher/emdash/tree/feat/nesting-block |
|
@louisescher thanks for putting this up. I rebased it onto 0.31.1 and have been building pages with it. Three things worth raising here rather than in the PR. The drag handle needs a different unit inside a container, and I am not certain mine is the right answer. With nested targeting on, the default rules resolve the unit inside a structure: for a list, the item. In a page built from containers a list is one row the page is made of, so I replaced them with a rule where a row is a child of the document or a child of a column. That matches what the editor does with nesting off and extends it one level down, so nothing outside a container changes. It also keeps a list movable as a block, which the defaults do not allow anywhere once The gutter the handle sits in has to belong to the row, not the column. Padding the column leaves it outside every row's box, so a pointer there resolves to the column and the container wins. It reads as the handle jumping away as you reach for it. Depth is settled. One trap for anyone extending the block: the admin carries its own Portable Text converters in Draft PR: #2248 Your prototype commit is its base and stays yours. It is against It adds column width ratios, since equal columns cannot express a content and sidebar page, the drag handling above, and a collapsed state, because a page with a few containers was hard to scan without one. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Add a new "nesting" block which can act as a grid/flex container for markdown text and other blocks.
Background & Motivation
I work on a lot of sites which have a complex content structure that cannot be expressed by the current "text + content block" format that EmDash uses. Adding a "nested" block to express grids or other containers would solve these issues, for example for grids that a user fills in themselves without me making a single pre-filled component for them to use.
A workflow like that would lead to a lot of back and forth between a developer (or an agent) and the person editing the site every time a component is adjusted, and requires a new deployment to register the component. That, is friction I would like to avoid.
Goals
Example
A three-up feature grid the editor fills in themselves. In Portable Text the block is a single node whose
childrenis an ordinary array of blocks:{ "_type": "nesting", "_key": "n1", "layout": "grid", // "grid" | "flex" "columns": 3, // grid: track count; flex: wrap target "gap": "1.5rem", "align": "stretch", "children": [ // ...editor adds/removes/reorders freely ] }Children are the same block types available at the top level (standard text blocks and plugin blocks), so the container is content-type-agnostic. Layout is expressed by a handful of scalar props on the container which the renderer maps them to CSS grid/flex.
Rendered:
Proposed design
Data model
nestingis a custom Portable Text object with:layout,columns,gap,align, optional per-breakpoint overrides), andchildrenarray of Portable Text nodesEditor
Currently, EmDash only produces scalar form fields, which TipTap renders as
atomnote views, which is fine for storing the data described above, but not for the UI logic required to make this proposal work.Real in-editor nesting needs a content-holding TipTap node + node view + serializer support:
content: "block+"(a container that holds other blocks) instead of an atomchildrenarray@tiptap/extension-tablealready runs nested-content nodes inside EmDash's editor, so this is already implemented in some way.Impact on existing systems
A
childrenarray is invisible to any code that assumes flat blocks. These need to recurse intochildrenor they will miss the content stored inside it:All reactions