Repository navigation
Define the TipTap block's text block styles inside the text blocks - #6383
Conversation
99dd4ad to
7f44fdd
Compare
7f44fdd to
65a4c3e
Compare
|
We'll review this once #6382 (which is likely to change) has been merged. |
528abb4 to
b3586f0
Compare
b3586f0 to
4d1dede
Compare
0810ac3 to
f5b91b5
Compare
f5b91b5 to
c92054e
Compare
49987f3 to
da44477
Compare
The editor collected the styles of every text block and list into one list, keyed by name - the global form this pull request replaces. The node view rendered a name through whichever definition came first, which is why reusing a name with a different definition had to be rejected. The node view now takes the style from the node's own text block, or from the list the node sits in, the way the toolbar already offers them. Two text blocks can therefore define a name each their own way, and nothing has to be rejected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The only thing the API wants to know is whether anything offers a style at all, which decides whether the text block node carries a `textBlockStyle` attribute. It read that off the length of a list of all styles, collected and keyed by name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Next to `orderedList` and `unorderedList`, the options took the list the walk is inside and whether it is inside a list item - state the function passes to itself, which a caller had to tell apart from the configuration. `list` was even reassigned from the two list options along the way. An inner function now walks the content and keeps the configuration in its closure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oolbar too
The node view renders a list item's content with the styles of the innermost list it
sits in, and the API validates it against that same list. The toolbar asked
`isActive("orderedList")` first, which matches any ancestor: inside a bullet list
nested in an ordered one it offered the outer list's styles, wrote a style the inner
list doesn't offer, and left the editor with a style that renders as none and content
the API rejects.
The nearest-ancestor lookup moves out of the node view so the toolbar resolves the same
list.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| * If none is specified, the inline style is allowed everywhere. | ||
| */ | ||
| appliesTo?: TipTapTextBlockType[]; | ||
| appliesTo?: string[]; |
There was a problem hiding this comment.
Out of scope: Now that text block styles live inside text blocks, it's odd that inline styles specific to a text block don't. We could consider moving them into the text blocks config in a follow-up PR.
There was a problem hiding this comment.
Agreed, and worth doing - appliesTo is the last place where something is tied to a text block from the outside. A follow-up, not this stack, which is four pull requests deep already.
One thing that makes it more than a move of the same shape: an inline style is a mark, not a node attribute. A mark spans a selection and survives a type switch, so a text block can end up carrying one it doesn't offer - the case we just had to handle for textBlockStyle. And the API validates appliesTo (containsInvalidInlineStyleMarks), so content that is fine today can become invalid. Both are solvable, but it needs a decision on what happens to a mark whose text block no longer offers it, rather than only moving the configuration.
There was a problem hiding this comment.
Okay, seems better to leave it like this.
`resolveList` mirrored the Admin's signature and recorded whether a list is an `ol` or a `ul`. The Admin needs that to toggle and render the list; the API reads it nowhere, and which tag a list has follows from the option it was configured as. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s text block #6383 removed the `textBlockStyles` option, but this story still used it, so `cms-admin` no longer passed the type check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…6523) The lint workflow fails on main because the TipTap table debug story from #6477 configures its rich text block with `textBlockStyles`, which #6383 replaced with styles defined inside the text blocks. Both pull requests were merged independently, so the type check only breaks on main. --- _Generated by [Claude Code](https://claude.ai/code/session_0151DMC1snZUQ4g3CmW6DhRY)_ Co-authored-by: Claude <noreply@anthropic.com>
The styling select always offered a "Default" entry standing for "no
style", even where a design has no unstyled variant and every text block
is meant to carry one of the configured styles. Editors had to pick the
right style by hand on every new text block, and forgetting it produced
unstyled content.
A text block (or list) with a `defaultStyle` has no such state:
```tsx
createTipTapRichTextBlock({
textBlocks: [
{ name: "heading-1", label: "Heading 1", tag: "h1", styles: headlineStyles, defaultStyle: "headline300" },
{ name: "heading-2", label: "Heading 2", tag: "h2", styles: headlineStyles, defaultStyle: "headline400" },
],
});
```
The select drops its "Default" entry, and the style is applied to new
content and to every text block the editor creates without one —
pressing Enter at the end of a text block, the `Mod-Alt-<level>`
shortcuts, pasting. Rather than reimplementing each of those paths, a
ProseMirror plugin fills in a missing style on document change, so
opening older content leaves it untouched and does not mark the document
as changed. Switching the type keeps a style the new text block also
offers and falls back to its `defaultStyle` otherwise, and toggling a
list hands the text block to the list's styles or back — through the
toolbar buttons and `Mod-Shift-7`/`Mod-Shift-8` alike.
Because the default sits on the text block rather than on a tag, two
text blocks sharing a tag can have different defaults, and a text block
without one keeps its "Default" entry next to text blocks that have one.
Third of four stacked pull requests, on top of #6383 and #6382; #6385
splits the block's Storybook stories by topic.
## Example
`createTipTapRichTextBlock.test.ts`/`.test.tsx` cover the validation and
the content a default style produces. The Storybook story [Default Text
Block
Style](https://tiptap-text-block-default-style--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--default-text-block-style)
walks through a text block with a default, one without, and the styled
lists.
Session:
https://claude.ai/code/session_f3c6ad37-c68b-4187-85b6-2abe5aa95c35
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
A text block style had to be configured in two places: globally in
textBlockStyles, and again through anappliesTolisting the text block types it was allowed for. Which styles a text block offers could only be read by scanning every style'sappliesTo, and two text blocks sharing a tag could not be told apart at all.A text block now carries its style definitions directly, and
textBlockStylesis gone:Text blocks that offer the same style share its definition, which makes the shared set explicit instead of implying it through repeated names. A style's
elementreceives the tag of the text block it is applied to, so one definition works for several tags. A text block that needs no style choice carries its ownelementinstead ofstyles; the two exclude each other in the types, so a text block either offers a choice or renders one way, and the styling select is only shown where there is something to choose. Lists take the same shape instead ofappliesTo: ["ordered-list", "unordered-list"].The stored format is unchanged — a style is still identified by its
nameintextBlockStyle— so no migration is needed.Second of four stacked pull requests, on top of #6382; #6384 adds
defaultStyle, #6385 splits the block's Storybook stories by topic.Example
The unit tests in
createTipTapRichTextBlock.test.ts/.test.tsx, and in Storybook:Session: https://claude.ai/code/session_f3c6ad37-c68b-4187-85b6-2abe5aa95c35