Renderer

Typescript โค๏ธ

Renderer component

Install
yarn add @atlaskit/renderer
Source
Bundle
Changelog
Latest

113.1.2

Patch Changes

  • #118536 b46814682ebf8 - [ux] [ED-26716] Review and fix usage of querySelectors in renderer table
  • Updated dependencies

Note: This component is designed for internal Atlassian development.

External contributors will be able to use this component but will not be able to submit issues.

This component provides a renderer for ADF documents.

Usage

Use the component in your React app as follows:

import { ReactRenderer } from '@atlaskit/renderer'; ReactDOM.render(<ReactRenderer document={DOCUMENT} />, container);

Example

With Providers

Input
<Renderer>

Hello, World! Look I can do italic , strong and underlined text! and action mark and invalid action mark

My favourite emoji are :evilburns: :not-an-emoji:. What are yours?

Apr 2, 2019

 

Hi, my name is... My name is... My name is... My name is :D

This is a . And this is a broken

Mention with restricted access

Mentions with generic ids@here@all

This is a text with multiple spaces and tabs.

italiclinkstrike-throughstrongsubsupunderline red text

some inline code: const foo = bar();

fallback text in node.attrs.text
fallback text in node.text
[very unknown]

This is text content inside unknown block
This is also a piece of text inside unknown block
Madness?
This is
Sparta!

This is a line with
a hardbreak in it.

Showing a status: In progress

Paragraph with 1 level of indentation

Paragraph with 2 levels of indentation

Paragraph with 3 levels of indentation

Paragraph with 4 levels of indentation

Paragraph with 5 levels of indentation

Paragraph with 6 levels of indentation

Paragraph with center alignment

Paragraph with end alignment

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

Heading 1 with 1 level of indentation

Heading 3 with 3 levels of indentation

Heading 4 with 4 levels of indentation

Heading 5 with 5 levels of indentation
Heading 6 with 6 levels of indentation

Heading 2 with center alignment

Heading 3 with end alignment

This is a paragraph with a text node that contains a new line

Click me! www.atlassian.com

// Create a map. final IntIntOpenHashMap map = new IntIntOpenHashMap(); map.put(1, 2); map.put(2, 5); map.put(3, 10); int count = map.forEach(new IntIntProcedure() { int count; public void apply(int key, int value) { if (value >= 5) count++; } }).count; System.out.println("There are " + count + " values >= 5");
    • First list item

    • Second list item

    • Third list item

    // Create a map. final IntIntOpenHashMap map = new IntIntOpenHashMap(); map.put(1, 2); map.put(2, 5); map.put(3, 10);
    1. First list item

    2. Second list item

    3. Third list item

    All that is gold does not glitter, not all those who wander are lost; The old that is strong does not wither, deep roots are not reached by the frost.

    From the ashes a fire shall be woken, a light from the shadows shall spring; Renewed shall be blade that was broken, the crownless again shall be king.

    J.R.R. Tolkien, The Fellowship of the Ring.

    This is an info panel with bold text

    This is a note panel with bold text

    This is a tip panel with bold text

    This is a success panel with bold text

    This is a warning panel with bold text

    This is a error panel with bold text


    Do not use this image node; it may be removed at any time without notice.

    Do not use this image node; it may be removed at any time without notice.

    just text
    with mention
    Apr 5, 2019 with date
    with emoji
    multiline!
    dfsfdad
    ticked off plain text
    ticked off mention
    Apr 5, 2019 ticked off date
    with emoji
    Multiline!
    asd
    1. plain text
    2. all the stuff todo Apr 5, 2019
    3. multiline!
      asdf

    header

    header

    cell

    cell

    cell

    cell

    cell

    cell

    Media single without width defined

    Media single with link

    This is the default content of the extension

    Extreme node nesting example

     

    1
    Apr 3, 2019 bold FAB-1520 UI: Poor man's search

     

    2
    1. a

    2. b

    3. c

      1. d

      2. e

      3. g

      4. Apr 5, 2019

     

     

    Highlights: Light Gray, Light Teal, Light Lime, Light Orange, Light Magenta, Light Purple, Custom: black, Custom: white, Custom: red, Custom: yellow, With inline comment, No highlight

    Highlight over comment

    Comment over highlight

    Partially overlapping comment

    </Renderer>

    Best practices to prevent performance issues

    Avoid unnecessary props changes

    As any React component, if props change then it will likely result in a re-render.

    Unnecessary props changes will trigger component reconciliation and potential re-renders. This has caused render performance degradation for Editor and Renderer components in the past.

    Some common examples of props causing re-renders:

    // โŒ function returns new object each time getEventHandlers = () => ({ ...defaultHandlers, newHander: () => { ... } }); // โŒ creates new function each time onRenderComplete = () => { // ... } return ( <ReactRenderer // โŒ passes new object each time media={{ allowLinking: true, }} // โŒ called function returns new object each time eventHandlers={this.getEventHandlers()} // โŒ passes new function each time onComplete={onRenderComplete} // โŒ creates a new function each time onError={() => { ... }} //... />);

    Most of these can be generally avoided by following these best practices:

    • extracting static objects to module level constants
    • avoid passing brand new objects and anonymous functions as props upon every render
    • memoising props via helpers like useMemo()
    • use useCallback() for callbacks where applicable

    Other best practices for React

    Consider using windowing techniques if possible when rendering many Renderers (eg. viewing comments).

    For Renderer it is important to avoid redundant reconciliation as it can involve rendering many nested React components, depending on the document structure.

    Check out the React docs for more examples of optimizations.

    Avoid duplicated dependencies

    Ensure you have only have one version of Renderer sub-dependencies (adf-schema, editor-common, prosemirror-model, etc) in your output bundles.

    This has caused bugs and crashes on production in the past.

    The issue can be avoided by running de-duplication on the lock file or using resolutions for yarn/overrides for npm on the package.json.

    Use correct peer dependencies

    Make sure to use correct peer dependencies versions!

    For example, using newer versions of React or react-dom can cause unexpected issues with Renderer.

    Using transformers with the renderer

    You will need to use a transformer to convert your own storage format into the ADF before you pass it to the renderer. We have provided helper utility to simplify this process:

    import { BitbucketTransformer } from '@atlaskit/editor-bitbucket-transformer'; import { ReactRenderer, ADFEncoder } from '@atlaskit/renderer'; const adfEncoder = new ADFEncoder(schema => new BitbucketTransformer(schema)); const document = adfEncoder.encode(DOCUMENT); ReactDOM.render(<ReactRenderer document={document} />, container);

    Polyfills

    Don't forget to add polyfills for fetch, ES6 & ES7 to your product build if you want to target older browsers. We recommend the use of babel-preset-env & babel-polyfill

    Truncated renderer

    The renderer can be truncated with a fade to white so that excess content is hidden. Control of expanding is left to the parent so the text and links can be customised - see the example.

    The props truncated, maxHeight and fadeOutHeight are all optional. maxHeight will default to 95px and fadeOutHeight will default to 30px unless defined.

    import { ReactRenderer } from '@atlaskit/renderer'; ReactDOM.render(<ReactRenderer document={DOCUMENT} truncated={true} maxHeight={70} fadeOutHeight={30} />, container);

    Truncated

    Input
    <Renderer>

    Hello, World! Look I can do italic , strong and underlined text! and action mark and invalid action mark

    My favourite emoji are ๐Ÿ˜ :evilburns: :not-an-emoji:. What are yours?

    Apr 2, 2019

     

    Hi, my name is... My name is... My name is... My name is @Oscar Wallhult :D

    This is a @mention. And this is a broken @unknown

    Mention with restricted access@oscar

    Mentions with generic ids@here@all

    This is a text with multiple spaces and tabs.

    italiclinkstrike-throughstrongsubsupunderline red text

    some inline code: const foo = bar();

    fallback text in node.attrs.text
    fallback text in node.text
    [very unknown]

    This is text content inside unknown block
    This is also a piece of text inside unknown block
    Madness?
    This is
    Sparta!

    This is a line with
    a hardbreak in it.

    Showing a status: In progress

    Paragraph with 1 level of indentation

    Paragraph with 2 levels of indentation

    Paragraph with 3 levels of indentation

    Paragraph with 4 levels of indentation

    Paragraph with 5 levels of indentation

    Paragraph with 6 levels of indentation

    Paragraph with center alignment

    Paragraph with end alignment

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Heading 5
    Heading 6

    Heading 1 with 1 level of indentation

    Heading 3 with 3 levels of indentation

    Heading 4 with 4 levels of indentation

    Heading 5 with 5 levels of indentation
    Heading 6 with 6 levels of indentation

    Heading 2 with center alignment

    Heading 3 with end alignment

    This is a paragraph with a text node that contains a new line

    Click me! www.atlassian.com

    // Create a map. final IntIntOpenHashMap map = new IntIntOpenHashMap(); map.put(1, 2); map.put(2, 5); map.put(3, 10); int count = map.forEach(new IntIntProcedure() { int count; public void apply(int key, int value) { if (value >= 5) count++; } }).count; System.out.println("There are " + count + " values >= 5");
      • First list item

      • Second list item

      • Third list item

      // Create a map. final IntIntOpenHashMap map = new IntIntOpenHashMap(); map.put(1, 2); map.put(2, 5); map.put(3, 10);
      1. First list item

      2. Second list item

      3. Third list item

      All that is gold does not glitter, not all those who wander are lost; The old that is strong does not wither, deep roots are not reached by the frost.

      From the ashes a fire shall be woken, a light from the shadows shall spring; Renewed shall be blade that was broken, the crownless again shall be king.

      J.R.R. Tolkien, The Fellowship of the Ring.

      This is an info panel with bold text

      This is a note panel with bold text

      This is a tip panel with bold text

      This is a success panel with bold text

      This is a warning panel with bold text

      This is a error panel with bold text


      Do not use this image node; it may be removed at any time without notice.

      Do not use this image node; it may be removed at any time without notice.

      just text
      @Carolyn with mention
      Apr 5, 2019 with date
      with emoji ๐Ÿ™‚
      multiline!
      dfsfdad
      ticked off plain text
      @Carolyn ticked off mention
      Apr 5, 2019 ticked off date
      with emoji ๐Ÿ™‚
      Multiline!
      asd
      1. plain text
      2. all the stuff ๐Ÿ™‚ todo Apr 5, 2019 @Carolyn
      3. multiline!
        asdf

      header

      header

      cell

      cell

      cell

      cell

      cell

      cell

      Media single without width defined

      Media single with link

      This is the default content of the extension

      Extreme node nesting example

       

      1
      @Carolyn Apr 3, 2019 ๐Ÿ™‚ bold FAB-1520 UI: Poor man's search

       

      2
      1. a

      2. b

      3. c

        1. d

        2. e

        3. g

        4. @Carolyn Apr 5, 2019

       

       

      Highlights: Light Gray, Light Teal, Light Lime, Light Orange, Light Magenta, Light Purple, Custom: black, Custom: white, Custom: red, Custom: yellow, With inline comment, No highlight

      Highlight over comment

      Comment over highlight

      Partially overlapping comment

       ยท 
      </Renderer>

      Theming and dark mode support

      To render certain ADF content correctly in different color themes, such as light and dark mode, this package utilise the @atlaskit/editor-palette package, which converts colors stored in ADF to Atlassian Design Tokens. Learn more about this utility in the Editor Palette docs.

      Full light and dark mode support for the Editor is a work in progress. Currently, the following experiences do not yet support theming:

      • Custom table backgrounds

      Props

      document import required

      @atlaskit/adf-schema.DocNode

      dataProviders import

      @atlaskit/editor-common/provider-factory.ProviderFactory

      eventHandlers import

      @atlaskit/editor-common/ui.EventHandlers

      extensionHandlers import

      @atlaskit/editor-common/extensions.ExtensionHandlers

      enableSsrInlineScripts boolean

      Enables inline scripts to add support for breakout nodes, before main JavaScript bundle is available.

      noOpSSRInlineScript boolean

      Enables inline scripts from above on client for first render for hydration to prevent mismatch.

      onComplete function

      stat => undefined

      onError function

      Ignored via go/ees005

      error => undefined

      portal HTMLElement

      HTMLElement

      rendererContext export

      RendererContext

      schema import

      @atlaskit/editor-prosemirror/model.Schema

      appearance union

      One of
      "comment",
      "full-page",
      "full-width",
      undefined

      adfStage import

      @atlaskit/editor-common/validator.ADFStage

      disableHeadingIDs boolean

      disableActions boolean

      allowPlaceholderText boolean

      maxHeight number

      fadeOutHeight number

      truncated boolean

      createAnalyticsEvent import

      @atlaskit/analytics-next.CreateUIAnalyticsEvent

      allowColumnSorting boolean

      shouldOpenMediaViewer boolean

      allowAltTextOnImages boolean

      stickyHeaders union

      One of
      boolean,
      show boolean
      &
      offsetTop number
      &
      defaultScrollRootId_DO_NOT_USE string
      shouldAddDefaultScrollRootOffsetTop_DO_NOT_USE boolean

      media object

      allowLinking boolean
      enableDownloadButton boolean
      featureFlags @atlaskit/media-common.MediaFeatureFlags
      ssr
      mode required @atlaskit/media-common.SSR
      config required @atlaskit/media-core.MediaClientConfig
      allowCaptions boolean

      emojiResourceConfig import

      @atlaskit/emoji/resource.EmojiResourceConfig

      allowAnnotations boolean

      annotationProvider union

      One of
      @atlaskit/editor-common/types.AnnotationProviders,
      null

      innerRef React.RefObject<HTMLDivElement>

      React.RefObjectHTMLDivElement

      useSpecBasedValidator boolean deprecated

      {@link https://hello.atlassian.net/browse/ENGHEALTH-3649 Internal documentation for deprecation (no external access)} This prop will be removed and set as default enabled, as the same flag on the Editor is also now default enabled.

      allowCopyToClipboard boolean

      allowWrapCodeBlock boolean

      allowCustomPanels boolean

      analyticsEventSeverityTracking object

      enabled boolean required
      severityNormalThreshold number required
      severityDegradedThreshold number required

      allowUgcScrubber boolean

      allowSelectAllTrap boolean

      unsupportedContentLevelsTracking import

      @atlaskit/editor-common/utils.UnsupportedContentLevelsTracking

      nodeComponents object

      [key: string] required React.ComponentTypeReact.PropsWithChildrenany

      isInsideOfInlineExtension boolean

      isTopLevelRenderer boolean

      includeNodesCountInStats boolean

      addTelepointer boolean

      • When enabled a trailing telepointer will be added to the rendered document
      • following content updates.
      • Content is updated by passing a new value prop to the renderer.
      • The trailing pointer is updated by dom injection to the last text node which
      • is updated as a result of a content update.

      featureFlags union

      • @default undefined
      • @description
      • Short lived feature flags for experiments and gradual rollouts
      • Flags are expected to follow these rules or they are filtered out
        1. cased in kebab-case (match [a-z-])
        1. have boolean values or object {} values
      • @example
      • (<Renderer featureFlags={{ 'my-feature': true }} />);
      • getFeatureFlags()?.myFeature === true;
      • @example
      • (<Renderer featureFlags={{ 'my-feature': 'thing' }} />);
      • getFeatureFlags()?.myFeature === undefined;
      • @example
      • (<Renderer featureFlags={{ 'product.my-feature': false }} />);
      • getFeatureFlags()?.myFeature === undefined;
      • getFeatureFlags()?.productMyFeature === undefined;
      One of
      [featureFlag: string] boolean required
      ,
      Partial
      renderer-render-tracking string required

      UNSTABLE_textHighlighter object

      pattern required RegExp
      component required React.ComponentType
      children required React.ReactNode
      match string required
      marks required Setstring
      groups union required One of
      Arraystring,
      undefined
      startPos number required

      UNSTABLE_allowTableAlignment boolean

      UNSTABLE_allowTableResizing boolean