@mirrormedia/lilith-draft-editor 1.0.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/lib/draft-js/block-renderer/background-image-block.tsx +113 -0
  2. package/lib/draft-js/block-renderer/background-video-block.tsx +120 -0
  3. package/lib/draft-js/block-renderer/color-box-block.tsx +85 -0
  4. package/lib/draft-js/block-renderer/divider-block.tsx +12 -0
  5. package/lib/draft-js/block-renderer/embedded-code-block.tsx +65 -0
  6. package/lib/draft-js/block-renderer/image-block.tsx +41 -0
  7. package/lib/draft-js/block-renderer/info-box-block.tsx +85 -0
  8. package/lib/draft-js/block-renderer/media-block.tsx +36 -0
  9. package/lib/draft-js/block-renderer/related-post-block.tsx +47 -0
  10. package/lib/draft-js/block-renderer/side-index-block.tsx +113 -0
  11. package/lib/draft-js/block-renderer/slideshow-block.tsx +62 -0
  12. package/lib/draft-js/block-renderer/table-block.tsx +488 -0
  13. package/lib/draft-js/buttons/annotation.tsx +113 -0
  14. package/lib/draft-js/buttons/background-color.tsx +125 -0
  15. package/lib/draft-js/buttons/background-image.tsx +276 -0
  16. package/lib/draft-js/buttons/background-video.tsx +275 -0
  17. package/lib/draft-js/buttons/color-box.tsx +207 -0
  18. package/lib/draft-js/buttons/divider.tsx +56 -0
  19. package/lib/draft-js/buttons/embedded-code.tsx +126 -0
  20. package/lib/draft-js/buttons/enlarge.tsx +11 -0
  21. package/lib/draft-js/buttons/font-color.tsx +113 -0
  22. package/lib/draft-js/buttons/image.tsx +71 -0
  23. package/lib/draft-js/buttons/info-box.tsx +170 -0
  24. package/lib/draft-js/buttons/link.tsx +103 -0
  25. package/lib/draft-js/buttons/media.tsx +120 -0
  26. package/lib/draft-js/buttons/related-post.tsx +81 -0
  27. package/lib/draft-js/buttons/selector/align-selector.tsx +65 -0
  28. package/lib/draft-js/buttons/selector/image-selector.tsx +485 -0
  29. package/lib/draft-js/buttons/selector/pagination.tsx +83 -0
  30. package/lib/draft-js/buttons/selector/post-selector.tsx +367 -0
  31. package/lib/draft-js/buttons/selector/search-box.tsx +39 -0
  32. package/lib/draft-js/buttons/selector/video-selector.tsx +312 -0
  33. package/lib/draft-js/buttons/side-index.tsx +257 -0
  34. package/lib/draft-js/buttons/slideshow.tsx +81 -0
  35. package/lib/draft-js/buttons/table.tsx +63 -0
  36. package/lib/draft-js/buttons/text-align.tsx +88 -0
  37. package/lib/draft-js/editor/basic-editor.tsx +384 -0
  38. package/lib/draft-js/editor/block-redender-fn.tsx +77 -0
  39. package/lib/draft-js/editor/draft-converter/api-data-instance.js +58 -0
  40. package/lib/draft-js/editor/draft-converter/atomic-block-processor.js +233 -0
  41. package/lib/draft-js/editor/draft-converter/entities.js +76 -0
  42. package/lib/draft-js/editor/draft-converter/index.js +201 -0
  43. package/lib/draft-js/editor/draft-converter/inline-styles-processor.js +238 -0
  44. package/lib/draft-js/editor/entity-decorator.tsx +7 -0
  45. package/lib/draft-js/editor/modifier.tsx +71 -0
  46. package/lib/draft-js/entity-decorator/annotation-decorator.tsx +81 -0
  47. package/lib/draft-js/entity-decorator/link-decorator.tsx +27 -0
  48. package/lib/index.js +31 -0
  49. package/lib/website/mirrormedia/custom/block-renderer/background-image-block.tsx +128 -0
  50. package/lib/website/mirrormedia/custom/block-renderer/background-video-block.tsx +135 -0
  51. package/lib/website/mirrormedia/custom/block-renderer/color-box-block.tsx +98 -0
  52. package/lib/website/mirrormedia/custom/block-renderer/divider-block.tsx +12 -0
  53. package/lib/website/mirrormedia/custom/block-renderer/embedded-code-block.tsx +65 -0
  54. package/lib/website/mirrormedia/custom/block-renderer/image-block.tsx +41 -0
  55. package/lib/website/mirrormedia/custom/block-renderer/info-box-block.tsx +98 -0
  56. package/lib/website/mirrormedia/custom/block-renderer/media-block.tsx +36 -0
  57. package/lib/website/mirrormedia/custom/block-renderer/related-post-block.tsx +47 -0
  58. package/lib/website/mirrormedia/custom/block-renderer/side-index-block.tsx +125 -0
  59. package/lib/website/mirrormedia/custom/block-renderer/slideshow-block.tsx +62 -0
  60. package/lib/website/mirrormedia/custom/block-renderer/table-block.tsx +537 -0
  61. package/lib/website/mirrormedia/custom/entity-decorator/annotation-decorator.tsx +81 -0
  62. package/lib/website/mirrormedia/custom/entity-decorator/link-decorator.tsx +27 -0
  63. package/lib/website/mirrormedia/custom/selector/align-selector.tsx +65 -0
  64. package/lib/website/mirrormedia/custom/selector/image-selector.tsx +485 -0
  65. package/lib/website/mirrormedia/custom/selector/pagination.tsx +83 -0
  66. package/lib/website/mirrormedia/custom/selector/post-selector.tsx +367 -0
  67. package/lib/website/mirrormedia/custom/selector/search-box.tsx +39 -0
  68. package/lib/website/mirrormedia/custom/selector/video-selector.tsx +310 -0
  69. package/lib/website/mirrormedia/draft-editor/block-redender-fn.tsx +77 -0
  70. package/lib/website/mirrormedia/draft-editor/entity-decorator.tsx +7 -0
  71. package/lib/website/mirrormedia/draft-editor/index.tsx +909 -0
  72. package/lib/website/mirrormedia/draft-renderer/block-redender-fn.tsx +77 -0
  73. package/lib/website/mirrormedia/draft-renderer/entity-decorator.tsx +7 -0
  74. package/lib/website/mirrormedia/draft-renderer/index-deprecated.tsx +43 -0
  75. package/lib/website/mirrormedia/draft-renderer/index.tsx +150 -0
  76. package/lib/website/mirrormedia/index.js +19 -0
  77. package/lib/website/readr/custom/block-renderer/background-image-block.tsx +128 -0
  78. package/lib/website/readr/custom/block-renderer/background-video-block.tsx +135 -0
  79. package/lib/website/readr/custom/block-renderer/color-box-block.tsx +98 -0
  80. package/lib/website/readr/custom/block-renderer/divider-block.tsx +12 -0
  81. package/lib/website/readr/custom/block-renderer/embedded-code-block.tsx +65 -0
  82. package/lib/website/readr/custom/block-renderer/image-block.tsx +41 -0
  83. package/lib/website/readr/custom/block-renderer/info-box-block.tsx +98 -0
  84. package/lib/website/readr/custom/block-renderer/media-block.tsx +36 -0
  85. package/lib/website/readr/custom/block-renderer/related-post-block.tsx +47 -0
  86. package/lib/website/readr/custom/block-renderer/side-index-block.tsx +125 -0
  87. package/lib/website/readr/custom/block-renderer/slideshow-block.tsx +62 -0
  88. package/lib/website/readr/custom/block-renderer/table-block.tsx +537 -0
  89. package/lib/website/readr/custom/entity-decorator/annotation-decorator.tsx +81 -0
  90. package/lib/website/readr/custom/entity-decorator/link-decorator.tsx +27 -0
  91. package/lib/website/readr/custom/selector/align-selector.tsx +65 -0
  92. package/lib/website/readr/custom/selector/image-selector.tsx +485 -0
  93. package/lib/website/readr/custom/selector/pagination.tsx +83 -0
  94. package/lib/website/readr/custom/selector/post-selector.tsx +367 -0
  95. package/lib/website/readr/custom/selector/search-box.tsx +39 -0
  96. package/lib/website/readr/custom/selector/video-selector.tsx +310 -0
  97. package/lib/website/readr/draft-editor/block-redender-fn.tsx +77 -0
  98. package/lib/website/readr/draft-editor/entity-decorator.tsx +7 -0
  99. package/lib/website/readr/draft-editor/index.tsx +909 -0
  100. package/lib/website/readr/draft-renderer/block-redender-fn.tsx +77 -0
  101. package/lib/website/readr/draft-renderer/entity-decorator.tsx +7 -0
  102. package/lib/website/readr/draft-renderer/index-deprecated.tsx +43 -0
  103. package/lib/website/readr/draft-renderer/index.tsx +150 -0
  104. package/lib/website/readr/index.js +19 -0
  105. package/package.json +39 -0
@@ -0,0 +1,65 @@
1
+ import React, { useEffect, useRef } from 'react'
2
+ import { DraftEntityInstance } from 'draft-js'
3
+ import { Block, Caption } from '../../../../draft-js/buttons/embedded-code'
4
+
5
+ export const EmbeddedCodeBlock = (entity: DraftEntityInstance) => {
6
+ const { caption, embeddedCode } = entity.getData()
7
+ const embedded = useRef(null)
8
+
9
+ useEffect(() => {
10
+ if (!embedded.current) return
11
+ const node: HTMLElement = embedded.current
12
+
13
+ const fragment = document.createDocumentFragment()
14
+
15
+ // `embeddedCode` is a string, which may includes
16
+ // multiple '<script>' tags and other html tags.
17
+ // For executing '<script>' tags on the browser,
18
+ // we need to extract '<script>' tags from `embeddedCode` string first.
19
+ //
20
+ // The approach we have here is to parse html string into elements,
21
+ // and we could use DOM element built-in functions,
22
+ // such as `querySelectorAll` method, to query '<script>' elements,
23
+ // and other non '<script>' elements.
24
+ const parser = new DOMParser()
25
+ const ele = parser.parseFromString(
26
+ `<div id="draft-embed">${embeddedCode}</div>`,
27
+ 'text/html'
28
+ )
29
+ const scripts = ele.querySelectorAll('script')
30
+ const nonScripts = ele.querySelectorAll('div#draft-embed > :not(script)')
31
+
32
+ nonScripts.forEach((ele) => {
33
+ fragment.appendChild(ele)
34
+ })
35
+
36
+ scripts.forEach((s) => {
37
+ const scriptEle = document.createElement('script')
38
+ const attrs = s.attributes
39
+ for (let i = 0; i < attrs.length; i++) {
40
+ scriptEle.setAttribute(attrs[i].name, attrs[i].value)
41
+ }
42
+ scriptEle.text = s.text || ''
43
+ fragment.appendChild(scriptEle)
44
+ })
45
+
46
+ node.appendChild(fragment)
47
+ }, [embeddedCode])
48
+
49
+ return (
50
+ <div>
51
+ {
52
+ // WORKAROUND:
53
+ // The following `<input>` is to solve [issue 153](https://github.com/mirror-media/openwarehouse-k6/issues/153).
54
+ // If the emebed code generates `<input>` or `<textarea>` and appends them onto DOM,
55
+ // and then the generated `<input>` or `<textarea>` will hijack the users' cursors.
56
+ // It will cause that users could not edit the DraftJS Editor anymore.
57
+ // The following phony `<input>` is used to prevent the generated `<input>` or `<textare>` from
58
+ // hijacking the users' cursors.
59
+ }
60
+ <input hidden disabled />
61
+ <Block ref={embedded} />
62
+ {caption ? <Caption>{caption}</Caption> : null}
63
+ </div>
64
+ )
65
+ }
@@ -0,0 +1,41 @@
1
+ import React from 'react'
2
+ import styled from 'styled-components'
3
+ import { DraftEntityInstance } from 'draft-js'
4
+
5
+ const Image = styled.img`
6
+ width: 100%;
7
+ `
8
+
9
+ const Figure = styled.figure`
10
+ margin-block: unset;
11
+ margin-inline: unset;
12
+ margin: 0 10px;
13
+ `
14
+
15
+ const Anchor = styled.a`
16
+ text-decoration: none;
17
+ `
18
+
19
+ export function ImageBlock(entity: DraftEntityInstance) {
20
+ const { desc, imageFile, resized, url } = entity.getData()
21
+
22
+ let imgBlock = (
23
+ <Figure>
24
+ <Image
25
+ src={resized?.w800}
26
+ onError={(e) => (e.currentTarget.src = imageFile?.url)}
27
+ />
28
+ <figcaption>{desc}</figcaption>
29
+ </Figure>
30
+ )
31
+
32
+ if (url) {
33
+ imgBlock = (
34
+ <Anchor href={url} target="_blank">
35
+ {imgBlock}
36
+ </Anchor>
37
+ )
38
+ }
39
+
40
+ return imgBlock
41
+ }
@@ -0,0 +1,98 @@
1
+ import React, { useState } from 'react'
2
+ import { ContentBlock, ContentState } from 'draft-js'
3
+ import styled from 'styled-components'
4
+ import draftConverter from '../../../../draft-js/editor/draft-converter'
5
+ import { InfoBoxInput } from '../../../../draft-js/buttons/info-box'
6
+
7
+ const InfoBoxRenderWrapper = styled.div`
8
+ background-color: #f5f4f3;
9
+ padding: 30px;
10
+ position: relative;
11
+ `
12
+
13
+ const InfoBoxRenderButton = styled.div`
14
+ cursor: pointer;
15
+ `
16
+
17
+ type InfoBoxBlockProps = {
18
+ block: ContentBlock
19
+ blockProps: {
20
+ onEditStart: () => void
21
+ onEditFinish: ({
22
+ entityKey,
23
+ entityData,
24
+ }: {
25
+ entityKey?: string
26
+ entityData?: Record<string, unknown>
27
+ }) => void
28
+ }
29
+ contentState: ContentState
30
+ }
31
+
32
+ export function InfoBoxBlock(props: InfoBoxBlockProps) {
33
+ const { block, contentState } = props
34
+ const entityKey = block.getEntityAt(0)
35
+ const entity = contentState.getEntity(entityKey)
36
+ const { title, body } = entity.getData()
37
+
38
+ return (
39
+ <InfoBoxRenderWrapper>
40
+ <h2>{title}</h2>
41
+ <div dangerouslySetInnerHTML={{ __html: body }} />
42
+ </InfoBoxRenderWrapper>
43
+ )
44
+ }
45
+
46
+ export function InfoBoxEditorBlock(props: InfoBoxBlockProps) {
47
+ const [toShowInput, setToShowInput] = useState(false)
48
+ const { block, blockProps, contentState } = props
49
+ const { onEditStart, onEditFinish } = blockProps
50
+ const entityKey = block.getEntityAt(0)
51
+ const entity = contentState.getEntity(entityKey)
52
+ const { title, rawContentState } = entity.getData()
53
+ const onChange = ({
54
+ title: newTitle,
55
+ rawContentState: newRawContentState,
56
+ }) => {
57
+ // close `InfoBoxInput`
58
+ setToShowInput(false)
59
+
60
+ onEditFinish({
61
+ entityKey,
62
+ entityData: {
63
+ title: newTitle,
64
+ body: draftConverter.convertToHtml(newRawContentState),
65
+ rawContentState: newRawContentState,
66
+ },
67
+ })
68
+ }
69
+
70
+ return (
71
+ <React.Fragment>
72
+ <InfoBoxInput
73
+ title={title}
74
+ rawContentStateForInfoBoxEditor={rawContentState}
75
+ onChange={onChange}
76
+ onCancel={() => {
77
+ onEditFinish({})
78
+ setToShowInput(false)
79
+ }}
80
+ isOpen={toShowInput}
81
+ />
82
+ <div>
83
+ <InfoBoxBlock {...props} />
84
+ <InfoBoxRenderButton
85
+ onClick={() => {
86
+ // call `onEditStart` prop as we are trying to update the InfoBox entity
87
+ onEditStart()
88
+ // open `InfoBoxInput`
89
+ setToShowInput(true)
90
+ }}
91
+ >
92
+ <i className="fa-solid fa-pen"></i>
93
+ <span>Modify</span>
94
+ </InfoBoxRenderButton>
95
+ </div>
96
+ </React.Fragment>
97
+ )
98
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import { DraftEntityInstance } from 'draft-js'
3
+
4
+ const styles = {
5
+ media: {
6
+ width: '100%',
7
+ },
8
+ }
9
+
10
+ const Audio = (props) => {
11
+ return <audio controls src={props.src} style={styles.media} />
12
+ }
13
+
14
+ const Image = (props) => {
15
+ return <img src={props.src} style={styles.media} />
16
+ }
17
+
18
+ const Video = (props) => {
19
+ return <video controls src={props.src} style={styles.media} />
20
+ }
21
+
22
+ export const MediaBlock = (entity: DraftEntityInstance) => {
23
+ const { src } = entity.getData()
24
+ const type = entity.getType()
25
+
26
+ let media
27
+ if (type === 'audioLink') {
28
+ media = <Audio src={src} />
29
+ } else if (type === 'imageLink') {
30
+ media = <Image src={src} />
31
+ } else if (type === 'videoLink') {
32
+ media = <Video src={src} />
33
+ }
34
+
35
+ return media
36
+ }
@@ -0,0 +1,47 @@
1
+ import React from 'react'
2
+ import styled from 'styled-components'
3
+ import { DraftEntityInstance } from 'draft-js'
4
+
5
+ const RelatedPostRenderWrapper = styled.div`
6
+ display: flex;
7
+ width: 100%;
8
+ `
9
+
10
+ const RelatedPostItem = styled.div`
11
+ flex: 0 0 33.3333%;
12
+ border: 1px solid rgba(0, 0, 0, 0.05);
13
+ `
14
+
15
+ const RelatedPostImage = styled.img`
16
+ display: block;
17
+ width: 100%;
18
+ aspect-ratio: 2;
19
+ object-fit: cover;
20
+ `
21
+
22
+ const RelatedPostTitle = styled.p`
23
+ margin: 0;
24
+ padding: 12px;
25
+ `
26
+
27
+ export function RelatedPostBlock(entity: DraftEntityInstance) {
28
+ const { posts } = entity.getData()
29
+
30
+ return (
31
+ <React.Fragment>
32
+ <RelatedPostRenderWrapper>
33
+ {posts.map((post) => (
34
+ <RelatedPostItem key={post.id}>
35
+ <RelatedPostImage
36
+ src={post.heroImage?.resized?.original}
37
+ onError={(e) =>
38
+ (e.currentTarget.src = post.heroImage?.imageFile?.url)
39
+ }
40
+ />
41
+ <RelatedPostTitle>{post.name}</RelatedPostTitle>
42
+ </RelatedPostItem>
43
+ ))}
44
+ </RelatedPostRenderWrapper>
45
+ </React.Fragment>
46
+ )
47
+ }
@@ -0,0 +1,125 @@
1
+ import React, { useState } from 'react'
2
+ import { ContentBlock, ContentState } from 'draft-js'
3
+ import styled from 'styled-components'
4
+ import {
5
+ SideIndexInputOnChange,
6
+ SideIndexInput,
7
+ } from '../../../../draft-js/buttons/side-index'
8
+
9
+ const SideIndexBlockWrapper = styled.div`
10
+ display: flex;
11
+ align-items: center;
12
+ `
13
+
14
+ const SideIndexBlockButton = styled.div`
15
+ cursor: pointer;
16
+ margin-left: 20px;
17
+ `
18
+
19
+ const SideIndex = styled.span`
20
+ font-size: 16px;
21
+ margin-left: 20px;
22
+ `
23
+
24
+ type SideIndexBlockProps = {
25
+ block: ContentBlock
26
+ blockProps: {
27
+ onEditStart: () => void
28
+ onEditFinish: ({
29
+ entityKey,
30
+ entityData,
31
+ }: {
32
+ entityKey?: string
33
+ entityData?: Record<string, unknown>
34
+ }) => void
35
+ }
36
+ contentState: ContentState
37
+ }
38
+
39
+ export function SideIndexBlock(props: SideIndexBlockProps) {
40
+ const { block, contentState } = props
41
+ const entityKey = block.getEntityAt(0)
42
+ const entity = contentState.getEntity(entityKey)
43
+ const { h2Text, sideIndexText, sideIndexUrl } = entity.getData()
44
+
45
+ let sideIndexBlock
46
+ if (sideIndexUrl) {
47
+ sideIndexBlock = (
48
+ <a href={sideIndexUrl}>
49
+ <SideIndex>側欄: {sideIndexText ? sideIndexText : h2Text}</SideIndex>
50
+ </a>
51
+ )
52
+ } else {
53
+ sideIndexBlock = (
54
+ <h2>
55
+ {h2Text}
56
+ <SideIndex>側欄: {sideIndexText ? sideIndexText : h2Text}</SideIndex>
57
+ </h2>
58
+ )
59
+ }
60
+
61
+ return <SideIndexBlockWrapper>{sideIndexBlock}</SideIndexBlockWrapper>
62
+ }
63
+
64
+ export function SideIndexEditorBlock(props: SideIndexBlockProps) {
65
+ const [toShowInput, setToShowInput] = useState(false)
66
+ const { block, blockProps, contentState } = props
67
+ const { onEditStart, onEditFinish } = blockProps
68
+ const entityKey = block.getEntityAt(0)
69
+ const entity = contentState.getEntity(entityKey)
70
+ const {
71
+ h2Text,
72
+ sideIndexText,
73
+ sideIndexUrl,
74
+ sideIndexImage,
75
+ } = entity.getData()
76
+ const onChange: SideIndexInputOnChange = ({
77
+ h2Text,
78
+ sideIndexText,
79
+ sideIndexUrl,
80
+ sideIndexImage,
81
+ }) => {
82
+ // close `SideIndexInput`
83
+ setToShowInput(false)
84
+ onEditFinish({
85
+ entityKey,
86
+ entityData: {
87
+ h2Text,
88
+ sideIndexText,
89
+ sideIndexUrl,
90
+ sideIndexImage,
91
+ },
92
+ })
93
+ }
94
+
95
+ return (
96
+ <React.Fragment>
97
+ <SideIndexInput
98
+ h2Text={h2Text}
99
+ sideIndexText={sideIndexText}
100
+ sideIndexUrl={sideIndexUrl}
101
+ sideIndexImage={sideIndexImage}
102
+ onChange={onChange}
103
+ onCancel={() => {
104
+ onEditFinish({})
105
+ setToShowInput(false)
106
+ }}
107
+ isOpen={toShowInput}
108
+ />
109
+ <div>
110
+ <SideIndexBlock {...props} />
111
+ <SideIndexBlockButton
112
+ onClick={() => {
113
+ // call `onEditStart` prop as we are trying to update the SideIndex entity
114
+ onEditStart()
115
+ // open `SideIndexInput`
116
+ setToShowInput(true)
117
+ }}
118
+ >
119
+ <i className="fa-solid fa-pen"></i>
120
+ <span>Modify</span>
121
+ </SideIndexBlockButton>
122
+ </div>
123
+ </React.Fragment>
124
+ )
125
+ }
@@ -0,0 +1,62 @@
1
+ import React from 'react'
2
+ import styled from 'styled-components'
3
+ import { DraftEntityInstance } from 'draft-js'
4
+
5
+ const Image = styled.img`
6
+ width: 100%;
7
+ `
8
+
9
+ const SlideshowCount = styled.div`
10
+ position: absolute;
11
+ top: 50%;
12
+ left: 50%;
13
+ border-radius: 100%;
14
+ border: black 1px solid;
15
+ transform: translate(-50%, -50%);
16
+ background-color: white;
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ flex-direction: column;
21
+ aspect-ratio: 1;
22
+ min-height: 66px;
23
+ padding: 10px;
24
+ `
25
+
26
+ const Figure = styled.figure`
27
+ position: relative;
28
+ margin-block: unset;
29
+ margin-inline: unset;
30
+ margin: 0 10px;
31
+ `
32
+
33
+ // support old version of slideshow without delay propertiy
34
+ export function SlideshowBlock(entity: DraftEntityInstance) {
35
+ const images = entity.getData()
36
+ return (
37
+ <Figure>
38
+ <Image
39
+ src={images?.[0]?.resized?.w800}
40
+ onError={(e) => (e.currentTarget.src = images?.[0]?.imageFile?.url)}
41
+ />
42
+ <SlideshowCount>+{images.length}</SlideshowCount>
43
+ </Figure>
44
+ )
45
+ }
46
+
47
+ // 202206 latest version of slideshow, support delay property
48
+ export function SlideshowBlockV2(entity: DraftEntityInstance) {
49
+ const { images, delay } = entity.getData()
50
+ return (
51
+ <Figure>
52
+ <Image
53
+ src={images?.[0]?.resized?.w800}
54
+ onError={(e) => (e.currentTarget.src = images?.[0]?.imageFile?.url)}
55
+ />
56
+ <SlideshowCount>
57
+ <div>+{images.length}</div>
58
+ {delay && <div>{`${delay}s`}</div>}
59
+ </SlideshowCount>
60
+ </Figure>
61
+ )
62
+ }