Repository navigation
Split the TipTap block's stories by topic - #6385
VPS-Andreas wants to merge 1 commit into
Conversation
fbd6499 to
61e2a1d
Compare
VPS-Obi
left a comment
There was a problem hiding this comment.
Could we make this a separate PR outside of the stack? 🤔
61e2a1d to
1f73e23
Compare
|
I'd rather keep it here. The three pull requests below rewrite most of what these stories configure, and two of the stories being moved (Text Block Element, Default Text Block Style) only exist because of them. A separate pull request against It sits last in the stack, so it doesn't hold the others up, and once #6384 is merged it can simply be retargeted to |
1f73e23 to
01abfc2
Compare
01abfc2 to
0930f41
Compare
2a4b28a to
c5b780e
Compare
c5b780e to
f135818
Compare
f135818 to
3187e55
Compare
3187e55 to
4839dd5
Compare
4839dd5 to
c9683dc
Compare
0283fc3 to
7fe41c0
Compare
7fe41c0 to
00adc46
Compare
…e textBlocks (#6382) The text block type select could only offer a fixed paragraph entry plus every enabled heading level, in a fixed order. A design that wants two entries for the same tag — a display headline above a regular heading 1 — or a different order could not be configured. `textBlocks` configures the entries explicitly and decouples a text block from the tag it is stored as: ```tsx createTipTapRichTextBlock({ textBlocks: [ { name: "paragraph", label: "Paragraph", tag: "p" }, { name: "display", label: "Display", tag: "h1" }, { name: "heading-1", label: "Heading 1", tag: "h1" }, { name: "heading-2", label: "Heading 2", tag: "h2" }, ], defaultTextBlock: "paragraph", }); ``` Two entries on the same tag only stay apart if the content records which one the editor picked, so paragraphs and headings are stored as a single `textBlock` node that names its entry. The tag is not stored at all — it follows from the configuration. The name is therefore the only thing content carries, and a node's type, its level and its text block can no longer drift apart. The site renders by that name instead of by heading level: ```tsx const nodeMapping: Record<string, TipTapNodeHandler> = { textBlock: ({ node, children }) => <Typography variant={textBlockToVariant[node.attrs?.textBlock]}>{children}</Typography>, }; ``` Content written before this change — `paragraph` and `heading` nodes carrying a `level` — is converted when the block is loaded, by a vendor migration (#6401). A project needs no migration of its own. Its own migrations run after Dextinity's and therefore see the converted nodes, so one written against `{ type: "heading", attrs: { level } }` has to match `{ type: "textBlock", attrs: { textBlock } }` instead. Because every text block is the same node now, a list item's content expression can no longer keep a heading out of it. The editor takes the content out of the list when a heading is chosen there, turns a heading back into a paragraph when it is wrapped in a list, and the API rejects a heading text block inside a list item. First of four stacked pull requests: #6383 moves the styles into the text blocks, #6384 adds `defaultStyle`, #6385 splits the block's Storybook stories by topic. ## Example `createTipTapRichTextBlock.test.ts`/`.test.tsx` cover the configuration, the stored format and what a list item accepts, `buildTextBlockNodeMigration.test.ts` the conversion. In Storybook: - [Heading Levels](https://tiptap-text-blocks--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--heading-levels) - [Heading Only](https://tiptap-text-blocks--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--heading-only) - [Heading Only With Text Block Styles](https://tiptap-text-blocks--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--heading-only-with-text-block-styles) - [List Text Block](https://tiptap-text-blocks--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--list-text-block) Session: https://claude.ai/code/session_f3c6ad37-c68b-4187-85b6-2abe5aa95c35 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
00adc46 to
a34667b
Compare
a34667b to
f62d252
Compare
|
f62d252 to
be4e45a
Compare
be4e45a to
5f3dbbd
Compare
…6383) A text block style had to be configured in two places: globally in `textBlockStyles`, and again through an `appliesTo` listing the text block types it was allowed for. Which styles a text block offers could only be read by scanning every style's `appliesTo`, and two text blocks sharing a tag could not be told apart at all. A text block now carries its style definitions directly, and `textBlockStyles` is gone: ```tsx const headlineStyles: TipTapTextBlockStyle[] = [ { name: "headline300", label: "Headline 300", element: (props, Tag) => <Tag {...props} /> }, { name: "headline400", label: "Headline 400", element: (props, Tag) => <Tag {...props} /> }, ]; createTipTapRichTextBlock({ textBlocks: [ { name: "heading-1", label: "Heading 1", tag: "h1", styles: headlineStyles }, { name: "heading-2", label: "Heading 2", tag: "h2", styles: headlineStyles }, { name: "display", label: "Display", tag: "h1", element: (props, Tag) => <Tag style={{ fontSize: 64 }} {...props} /> }, ], orderedList: { styles: copyStyles }, }); ``` 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 `element` receives 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 own `element` instead of `styles`; 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 of `appliesTo: ["ordered-list", "unordered-list"]`. The stored format is unchanged — a style is still identified by its `name` in `textBlockStyle` — 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: - [Text Block Styles](https://tiptap-text-block-styles--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--text-block-styles) - [Text Block Style Interactions](https://tiptap-text-block-styles--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--text-block-style-interactions) - [List Text Block Styles](https://tiptap-text-block-styles--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--list-text-block-styles) - [Text Block Element](https://tiptap-text-block-styles--69df3371c46abe69b5199825.chromatic.com/?path=/story/blocks-tiptaprichtextblock--text-block-element) Session: https://claude.ai/code/session_f3c6ad37-c68b-4187-85b6-2abe5aa95c35 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
f337bc8 to
899c82c
Compare
The single stories file had grown to sixteen stories across every feature of the block, so finding the ones for a feature meant scrolling past all the others. The heading and text block style stories move into their own files, following the child block, inline style and translation files that were already split off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
899c82c to
b96c92b
Compare
TipTapRichTextBlock.stories.tsxhad grown past 1400 lines covering everything the block can do, so finding the story for a given feature meant scrolling past all the others — and the heading, list and text block style stories are exactly the ones the preceding pull requests keep touching.Those three groups move into files of their own, next to the child block, inline style and translation files that were already split off. No story or configuration changes, only the move: the Heading, List and TextBlockStyles sections now sit next to the block's remaining stories in Storybook.
The list file takes
ListLevelMaxandListTextBlockfrom the block's own file andListTextBlockStylesfrom the text block styles file. Three style fixtures it shares with the stories that stay behind are defined in both files, so each one reads on its own.Follows #6384, #6383 and #6382.
Changeset
None needed — Storybook stories are internal.
Session: https://claude.ai/code/session_f3c6ad37-c68b-4187-85b6-2abe5aa95c35