Skip to content

refactor types for blocks #412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Nov 29, 2023
Merged

Conversation

YousefED
Copy link
Collaborator

@YousefED YousefED commented Nov 15, 2023

This PR refactors some of the block typings. I think we were overly relying on generics and passing explicit types which made the code more difficult imo, and after some experimentation it turns out it's not really necessary.

Changes:

  • Separate blockConfig and blockImplementation, the config has all the info for the schema, and the implementation has details about rendering / serializing. A blockSpec now encapsulates both. The separation was necessary so that render and toExternalHTML can pass a block of the correct type, because the type needs to be based on blockConfig (this was difficult / impossible to do while defining them in the same object).
  • Moved all custom block related code to a separate file
  • Removed the TipTap related type code from blockTypes.ts. These were only used internally, and difficult to reason about / work with

Note: there is some table-related code in here, but it should be all disabled (I don't think this is a blocker, but we could remove it)

TODO:

  • update the documentation, as the separation of config and implementation is a breaking change
  • fix pw tests

Copy link

vercel bot commented Nov 15, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
blocknote-website ✅ Ready (Inspect) Visit Preview Nov 29, 2023 10:33am

Copy link
Collaborator

@matthewlipski matthewlipski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Think some of the typing could still be simplified and some of the names clash, but overall I like the changes and it's pretty clear that we probably did not need to be passing around BlockSchema generics as much internally.

In terms of actual fixes, this is mainly to fix toInternalHTML & toExternalHTML right? Or is there anything else?


// A BlockConfig has all the information to get the type of a Block (which is a specific instance of the BlockConfig.
// i.e.: paragraphConfig: BlockConfig defines what a "paragraph" is / supports, and BlockFromBlockConfig<paragraphConfig> is the shape of a specific paragraph block.
export type BlockFromBlockConfig<B extends BlockConfig> = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically what SpecificBlock was before right? I.e. an instance of a block where we know the type, props, and inline content it can have, but don't necessarily know what other blocks are in the schema, and therefore don't know the block types it can have as children. In which case I think the naming could be more explicit, e.g. BlockWithoutSchema.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also how come we use children: Block<any> instead of children: Block<BlockSchemaWithBlock<B["type], B["propSchema"]>>?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now moved it to Block, which can now either take a BlockSchema or BlockConfig as type parameter. The code is a bit more complex, but the naming is better I think

I couldn't get the second suggestion to work unfortunately.

export type BlockFromCustomBlockConfig<T extends CustomBlockConfig> =
BlockFromBlockConfig<BlockConfigFromCustomBlockConfig<T>>;

export type CustomBlockImplementation<T extends CustomBlockConfig> = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like between BlockImplementation and CustomBlockImplementation the naming is pretty confusing. From what I understand, consumers define a CustomBlockImplementation to control the output of their custom block in HTML. But BlockImplementation is only meant for internal use and has different fields, which imo is confusing since the names are nearly the same.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CustomBlockImplementation eventually maps to a BlockImplementation indeed.

Renamed to BlockImplementation to TiptapBlockImplementation because it's the type that eventually has a tiptap node


// Defines the config for a custom block. Meant to be used as an argument to
// `createBlockSpec`, which will create a new block spec from it.
export type CustomBlockConfig = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary if we already have BlockConfig? Seems like the only difference is containsInlineContent vs content, which basically determine the same thing anyway.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've simplified this, at the cost of a breaking change.

Users will need to specify content: "inline" instead of containsInlineContent: true


export function createInternalBlockSpec<T extends BlockConfig>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really weird function, it just returns the same object? Seems a bit hacky

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, it's a bit hacky. Added comment:

// This helper function helps to instantiate a blockspec with a
// config and implementation that conform to the type of Config

I couldn't get it working without (maybe it's possible with satisfies somewhere, this makes it easy to instantiate a blockImplementation with strongly typed render / externalhtml functions


// A function to create custom block for API consumers
// we want to hide the tiptap node from API consumers and provide a simpler API surface instead
export function createBlockSpec<T extends CustomBlockConfig>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to split the config & implementation when creating a custom block (since this is a breaking change)? I understand it helps to mirror the structure of BlockSpec, but implementation/blockImplementation is different between them either way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes. The issue is that I don't think it's easily possible to have 1 object where some properties depend of the value of another property, which is the case that we had with render(block) (type of block depends on the rest of the object). At least, I couldn't get it working

* fix table types

* add tablecontent

* clean BNUpdateBlock

* add partial inline content

* add contentNodeToTableContent

* first draft of tablehandles

* implement table functions

* fix styles

* fix imports

* create separate TableExtension

* improve types

* test some types

* Fixed setting selection for table blocks

* Fixed backspace deleting table if at start of cell

* small code fixes

* Implemented PR feedback

* Improved table row/column drag & drop UX

* Fixed table menus moving around, drag indicator flakiness, menu z-index issues, and drag preview

* Implemented PR feedback

* Implemented PR feedback

* Fixed drag handles sometimes not showing

* Fixed scrolling behaviour

* Small fixes

* Fixed table handles UI

* Fixed remaining UX/UI issues

* Removed redundant state from table handles plugin

* Implemented table drag & drop logic

* Added table enter handling

* Small fix

* feat: custom styles and custom inline content (#418)

* wip custom styles

* fix

* fix tests

* simplify PartialInlineContent

* custom inline content

* clean nodeconversions test

* streamline tests

* update tests

* move schema files

* add custom style test

* inline content + tests

* misc

* clean imports

* fix react tests

* add react nodeconversions tests

* move tests and add test for ReactStyles

* fix react tests

* basis of new examples

* add react examples

* fix bug

* misc fixes

* wip

* clean

* small cleanup

* add comments

* move funcs

* fix tests

* address PR feedback

* fix inline content types

* feat: HTML paste handling (#422)

* refactor parse

* fix parse-divsc

* add test case

* add extra test (that should be fixed)

* readd markdown functions

* fix tests

* remove unused file

* remove comments

* add comment

* nested list handling

* add todos

* added comment

* use refs for blocks (#424)

* use refs for blocks

* update react htmlConversion test

* Custom inline content and styles commands/copy & paste fixes (#425)

* Fixed commands and internal copy/paste for inline content

* Fixed internal copy/paste for styles

* Small cleanup

* fix some tests

---------

Co-authored-by: yousefed <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>

* use processSync

---------

Co-authored-by: Matthew Lipski <[email protected]>

* fix build

---------

Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>
@YousefED YousefED merged commit 650a9ac into custom-block-serialization Nov 29, 2023
YousefED added a commit that referenced this pull request Nov 29, 2023
* Added serialization for vanilla custom blocks

* Added serialization for React custom blocks

* Cleaned up serializer implementation - no longer uses function override

* Revert "Cleaned up serializer implementation - no longer uses function override"

This reverts commit b4f3fb6.

* Removed comment

* Added ability to set custom serialization and parse functions for custom blocks (parse still WIP)

* Fixed build and most runtime issues

* Added `react-dom` dependency

* Added PoC copy/paste handling

* Small changes & fixes

* Added serialization tests

* Changed copy/paste implementation

* Small fix

* Implemented PR feedback

* Converted styles from modules to regular CSS

* Implemented PR feedback

* Updated serialization test snapshots

* Updated serialization tests to use BlockNote API

* Commented out custom block parsing code (out of scope for this PR)

* Improved `nodeToBlock` typing

* Small fixes

* Fixed `destroy` function not getting passed to TipTap node view

* Updated comment regarding clipboard issues

* Major restructure of copy/paste code

* Reduced code duplication for HTML serializer & exporter

* Implemented PR feedback & cleaned up CSS class names

* Updated serialization unit test snapshots

* Changed `DOMOutputSpec` implementation for default blocks

* Fixed some CSS issues

* Implemented PR feedback

* Reverted `nodeToBlock` typing

* Made external HTML conversions no longer `async` and fixed Firefox clipboard reading

* Fixed image test issues and small changes

* Fixed remaining image test issues

* Updated serialization unit test snapshots

* Excluded `formatConversions` test

* Fixed HTML export for custom blocks with inline content

* Fixed duplicate `blockContainer` attributes getting added to custom blocks' `blockContent` nodes from color default props and changed `toExternalHTML` typing for React custom blocks

* Added React serialization unit tests and extra vanilla tests

* Updated image e2e snapshots

* Small e2e test fix

* Added comments

* Fixed error when copying only nested blocks

* refactor types for blocks (#412)

* refactor types for blocks

* remove unused comment

* fix test

* run tests on all branches

* fix build

* change BlockFromBlockConfig to Block

* simplify customblockconfig

* rename BlockImplementation to TiptapBlockImplementation

* fix build

* add comment

* feat: tables (#413)

* fix table types

* add tablecontent

* clean BNUpdateBlock

* add partial inline content

* add contentNodeToTableContent

* first draft of tablehandles

* implement table functions

* fix styles

* fix imports

* create separate TableExtension

* improve types

* test some types

* Fixed setting selection for table blocks

* Fixed backspace deleting table if at start of cell

* small code fixes

* Implemented PR feedback

* Improved table row/column drag & drop UX

* Fixed table menus moving around, drag indicator flakiness, menu z-index issues, and drag preview

* Implemented PR feedback

* Implemented PR feedback

* Fixed drag handles sometimes not showing

* Fixed scrolling behaviour

* Small fixes

* Fixed table handles UI

* Fixed remaining UX/UI issues

* Removed redundant state from table handles plugin

* Implemented table drag & drop logic

* Added table enter handling

* Small fix

* feat: custom styles and custom inline content (#418)

* wip custom styles

* fix

* fix tests

* simplify PartialInlineContent

* custom inline content

* clean nodeconversions test

* streamline tests

* update tests

* move schema files

* add custom style test

* inline content + tests

* misc

* clean imports

* fix react tests

* add react nodeconversions tests

* move tests and add test for ReactStyles

* fix react tests

* basis of new examples

* add react examples

* fix bug

* misc fixes

* wip

* clean

* small cleanup

* add comments

* move funcs

* fix tests

* address PR feedback

* fix inline content types

* feat: HTML paste handling (#422)

* refactor parse

* fix parse-divsc

* add test case

* add extra test (that should be fixed)

* readd markdown functions

* fix tests

* remove unused file

* remove comments

* add comment

* nested list handling

* add todos

* added comment

* use refs for blocks (#424)

* use refs for blocks

* update react htmlConversion test

* Custom inline content and styles commands/copy & paste fixes (#425)

* Fixed commands and internal copy/paste for inline content

* Fixed internal copy/paste for styles

* Small cleanup

* fix some tests

---------

Co-authored-by: yousefed <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>

* use processSync

---------

Co-authored-by: Matthew Lipski <[email protected]>

* fix build

---------

Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Yousef <[email protected]>
matthewlipski added a commit that referenced this pull request Dec 4, 2023
…copy / paste handling (#426)

* feat: Custom block serialization (#257)

* Added serialization for vanilla custom blocks

* Added serialization for React custom blocks

* Cleaned up serializer implementation - no longer uses function override

* Revert "Cleaned up serializer implementation - no longer uses function override"

This reverts commit b4f3fb6.

* Removed comment

* Added ability to set custom serialization and parse functions for custom blocks (parse still WIP)

* Fixed build and most runtime issues

* Added `react-dom` dependency

* Added PoC copy/paste handling

* Small changes & fixes

* Added serialization tests

* Changed copy/paste implementation

* Small fix

* Implemented PR feedback

* Converted styles from modules to regular CSS

* Implemented PR feedback

* Updated serialization test snapshots

* Updated serialization tests to use BlockNote API

* Commented out custom block parsing code (out of scope for this PR)

* Improved `nodeToBlock` typing

* Small fixes

* Fixed `destroy` function not getting passed to TipTap node view

* Updated comment regarding clipboard issues

* Major restructure of copy/paste code

* Reduced code duplication for HTML serializer & exporter

* Implemented PR feedback & cleaned up CSS class names

* Updated serialization unit test snapshots

* Changed `DOMOutputSpec` implementation for default blocks

* Fixed some CSS issues

* Implemented PR feedback

* Reverted `nodeToBlock` typing

* Made external HTML conversions no longer `async` and fixed Firefox clipboard reading

* Fixed image test issues and small changes

* Fixed remaining image test issues

* Updated serialization unit test snapshots

* Excluded `formatConversions` test

* Fixed HTML export for custom blocks with inline content

* Fixed duplicate `blockContainer` attributes getting added to custom blocks' `blockContent` nodes from color default props and changed `toExternalHTML` typing for React custom blocks

* Added React serialization unit tests and extra vanilla tests

* Updated image e2e snapshots

* Small e2e test fix

* Added comments

* Fixed error when copying only nested blocks

* refactor types for blocks (#412)

* refactor types for blocks

* remove unused comment

* fix test

* run tests on all branches

* fix build

* change BlockFromBlockConfig to Block

* simplify customblockconfig

* rename BlockImplementation to TiptapBlockImplementation

* fix build

* add comment

* feat: tables (#413)

* fix table types

* add tablecontent

* clean BNUpdateBlock

* add partial inline content

* add contentNodeToTableContent

* first draft of tablehandles

* implement table functions

* fix styles

* fix imports

* create separate TableExtension

* improve types

* test some types

* Fixed setting selection for table blocks

* Fixed backspace deleting table if at start of cell

* small code fixes

* Implemented PR feedback

* Improved table row/column drag & drop UX

* Fixed table menus moving around, drag indicator flakiness, menu z-index issues, and drag preview

* Implemented PR feedback

* Implemented PR feedback

* Fixed drag handles sometimes not showing

* Fixed scrolling behaviour

* Small fixes

* Fixed table handles UI

* Fixed remaining UX/UI issues

* Removed redundant state from table handles plugin

* Implemented table drag & drop logic

* Added table enter handling

* Small fix

* feat: custom styles and custom inline content (#418)

* wip custom styles

* fix

* fix tests

* simplify PartialInlineContent

* custom inline content

* clean nodeconversions test

* streamline tests

* update tests

* move schema files

* add custom style test

* inline content + tests

* misc

* clean imports

* fix react tests

* add react nodeconversions tests

* move tests and add test for ReactStyles

* fix react tests

* basis of new examples

* add react examples

* fix bug

* misc fixes

* wip

* clean

* small cleanup

* add comments

* move funcs

* fix tests

* address PR feedback

* fix inline content types

* feat: HTML paste handling (#422)

* refactor parse

* fix parse-divsc

* add test case

* add extra test (that should be fixed)

* readd markdown functions

* fix tests

* remove unused file

* remove comments

* add comment

* nested list handling

* add todos

* added comment

* use refs for blocks (#424)

* use refs for blocks

* update react htmlConversion test

* Custom inline content and styles commands/copy & paste fixes (#425)

* Fixed commands and internal copy/paste for inline content

* Fixed internal copy/paste for styles

* Small cleanup

* fix some tests

---------

Co-authored-by: yousefed <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>

* use processSync

---------

Co-authored-by: Matthew Lipski <[email protected]>

* fix build

---------

Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>

---------

Co-authored-by: Yousef <[email protected]>

* fix: change parse function to only return props

* fix lint

* add comment

* Made block, inline content, and style content get parsed from `contentDOM` instead of `dom`

* Small fixes

* Fixed table enter handling

* Updated unit tests

* Fixed parsing error when `dom` is same as `contentDOM` (#429)

* Fixed parsing error for styles/inline content where `dom` was the same as `contentDOM`

* Updated react snapshots

* Playground custom elements (#430)

* Added playgrounds for vanilla blocks, React blocks, and vanilla inline content

* fix renderHTML error

* clean examples

---------

Co-authored-by: yousefed <[email protected]>

* Add markdown tests (#428)

* update docs

* add markdown tests

* remove unused file

* add missing space to mention tests

* move and update playwright tests (#427)

* move and update playwright tests

* fix build

* fix test setup

* fix pw config

* fix test command

* Playwright refactor fixes (#436)

* Fixed issues with most tests

* Temporarily commented out failing unit test

* Temporarily commented out failing unit test

* Fixed remaining failing playwright tests

* Re-added test that was causing issues

* re-add tests

* add pw-report

* skip tests and edit css

* revert style

* add logs

* fix unit tests

---------

Co-authored-by: yousefed <[email protected]>

---------

Co-authored-by: Matthew Lipski <[email protected]>

* Block backspace key event at start of custom editable inline content (#435)

* Fixed parsing error for styles/inline content where `dom` was the same as `contentDOM`

* Updated react snapshots

* Blocked backspace at start of custom editable inline content

* add comment

---------

Co-authored-by: yousefed <[email protected]>

* fix empty table content

* update comments

* extract transformPasted

* widen slashmenu typings

* Updated docs for custom blocks and added tables (#442)

---------

Co-authored-by: Matthew Lipski <[email protected]>
Co-authored-by: Matthew Lipski <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants