Skip to content

Commit

Permalink
Merge pull request #21 from speee/allow-img-and-image
Browse files Browse the repository at this point in the history
Make interchangeable with Image component and intrinsic img tag
  • Loading branch information
Yuki Hattori authored Jun 28, 2019
2 parents 3ba9377 + eb3fab0 commit 9575a92
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 53 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Changed

- Make interchangeable with `<Image>` component and intrinsic `<img>` tag ([#21](https://github.com/speee/jsx-slack/pull/21))

## v0.4.3 - 2019-05-15

### Fixed
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ The content of `<Section>` may include one of an accessory component. A defined

###### Accessory components

- [`<Image>`](#image-image-block)
- [`<Image>` / `<img>`](#image-image-block)
- [`<Button>`](#button-button-element)
- [`<Select>`](#select-select-menu-with-static-options)
- [`<ExternalSelect>`](#externalselect-select-menu-with-external-data-source)
Expand Down Expand Up @@ -234,9 +234,7 @@ Just a divider. `<hr>` intrinsic HTML element works as well.

#### [`<Image>`: Image Block](https://api.slack.com/reference/messaging/blocks#image)

Display an image block. It has well-known props like `<img>` HTML element.

In `<Blocks>`, `<img>` intrinsic HTML element works as well.
Display an image block. It has well-known props like `<img>` HTML element. In fact, `<img>` intrinsic HTML element works as well.

```jsx
<Blocks>
Expand All @@ -263,7 +261,7 @@ A block to hold [interactive elements](#interactive-elements). Slack allows a ma

#### [`<Context>`: Context Block](https://api.slack.com/reference/messaging/blocks#context)

Display message context. It allows mixed contents consisted of the text and the `<img>` tag image.
Display message context. It allows mixed contents consisted of the text and the `<Image>` component / `<img>` tag.

```jsx
<Blocks>
Expand Down Expand Up @@ -539,6 +537,8 @@ Define confirmation dialog. Some interactive elements can open confirmation dial
[confirmation]: https://api.slack.com/tools/block-kit-builder?blocks=%5B%7B%22type%22%3A%22actions%22%2C%22elements%22%3A%5B%7B%22type%22%3A%22button%22%2C%22text%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Commit%22%2C%22emoji%22%3Atrue%7D%2C%22action_id%22%3A%22commit%22%2C%22confirm%22%3A%7B%22title%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Commit%20your%20action%22%2C%22emoji%22%3Atrue%7D%2C%22text%22%3A%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22*Are%20you%20sure%3F*%20Please%20confirm%20your%20action%20again.%22%2C%22verbatim%22%3Atrue%7D%2C%22confirm%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Yes%2C%20please%22%2C%22emoji%22%3Atrue%7D%2C%22deny%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Cancel%22%2C%22emoji%22%3Atrue%7D%7D%2C%22value%22%3A%22value%22%7D%5D%7D%5D
> :information_source: You can use [HTML-like formatting](#html-like-formatting) to the content of confirmation dialog. However, you have to be careful that Slack ignores any line breaks and the content will render just in a line.
##### Props
- `title` (**required**): The title of confirmation dialog.
Expand Down
21 changes: 18 additions & 3 deletions demo/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,23 @@ export default {
// Block Kit component
Section: {
attrs: blockCommonAttrs,
children: ['Field', 'Image', ...interactiveComponents, ...markupHTML],
children: [
'Field',
'Image',
'img',
...interactiveComponents,
...markupHTML,
],
},
section: {
attrs: { id: null },
children: ['Field', 'Image', ...interactiveComponents, ...markupHTML],
children: [
'Field',
'Image',
'img',
...interactiveComponents,
...markupHTML,
],
},
Field: { attrs: {}, children: markupHTML },
Divider: { attrs: blockCommonAttrs, children: [] },
Expand All @@ -70,7 +82,10 @@ export default {
children: [],
},
Actions: { attrs: blockCommonAttrs, children: interactiveComponents },
Context: { attrs: blockCommonAttrs, children: ['img', ...markupHTML] },
Context: {
attrs: blockCommonAttrs,
children: ['Image', 'img', ...markupHTML],
},

// Interactive components
Button: {
Expand Down
27 changes: 17 additions & 10 deletions src/block-kit/Context.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx JSXSlack.h */
import { ContextBlock, ImageElement, MrkdwnElement } from '@slack/types'
import { JSXSlack } from '../jsx'
import html from '../html'
import { JSXSlack } from '../jsx'
import { ObjectOutput } from '../utils'
import { BlockComponentProps } from './Blocks'

Expand All @@ -14,10 +14,21 @@ export const Context: JSXSlack.FC<
let current: (string | JSXSlack.Node)[] = []

for (const child of [...JSXSlack.normalizeChildren(children), endSymbol]) {
const img =
child && typeof child === 'object' && child.type === 'img'
? child
: undefined
const img = (() => {
if (typeof child !== 'object') return undefined

const { props } = child

// <img> intrinsic HTML element
if (child.type === 'img')
return { image_url: props.src, alt_text: props.alt }

// A converted <Image> component
if (child.type === JSXSlack.NodeType.object && props.type === 'image')
return { image_url: props.image_url, alt_text: props.alt_text }

return undefined
})()

if (current.length > 0 && (img || child === endSymbol)) {
// Text content
Expand All @@ -27,11 +38,7 @@ export const Context: JSXSlack.FC<

if (img) {
// Image content
elements.push({
type: 'image',
image_url: img.props.src,
alt_text: img.props.alt,
})
elements.push({ type: 'image', ...img })
} else if (typeof child !== 'symbol') {
current.push(child)
}
Expand Down
55 changes: 34 additions & 21 deletions src/block-kit/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { JSXSlack } from '../jsx'
import { ObjectOutput } from '../utils'
import html from '../html'
import { BlockComponentProps } from './Blocks'
import { Image } from './Image'

export const Section: JSXSlack.FC<
BlockComponentProps & { children: JSXSlack.Children<{}> }
Expand All @@ -14,30 +15,42 @@ export const Section: JSXSlack.FC<
let fields: SectionBlock['fields']

for (const child of JSXSlack.normalizeChildren(children)) {
if (typeof child === 'object' && child.type === JSXSlack.NodeType.object) {
let eaten = false

if (typeof child === 'object') {
// Accessory and fields
switch (child.props.type) {
case 'image':
case 'button':
case 'static_select':
case 'external_select':
case 'users_select':
case 'conversations_select':
case 'channels_select':
case 'overflow':
case 'datepicker':
accessory = JSXSlack(child)
break
case 'mrkdwn':
if (!fields) fields = []
fields.push(child.props)
break
default:
throw new Error('<Section> has unexpected component as accessory.')
if (child.type === JSXSlack.NodeType.object) {
switch (child.props.type) {
case 'image':
case 'button':
case 'static_select':
case 'external_select':
case 'users_select':
case 'conversations_select':
case 'channels_select':
case 'overflow':
case 'datepicker':
accessory = JSXSlack(child)
break
case 'mrkdwn':
if (!fields) fields = []
fields.push(child.props)
break
default:
throw new Error(
'<Section> has unexpected component as an accessory.'
)
}
eaten = true
} else if (child.type === 'img') {
accessory = JSXSlack(
<Image alt={child.props.alt} src={child.props.src} />
)
eaten = true
}
} else {
normalized.push(child)
}

if (!eaten) normalized.push(child)
}

const text = html(normalized)
Expand Down
40 changes: 26 additions & 14 deletions test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,23 @@ describe('jsx-slack', () => {
},
}

it('outputs section block with <Image> accessory', () =>
expect(
JSXSlack(
<Blocks>
<Section blockId="with_image">
Image example
<Image
src="https://example.com/image.jpg"
alt="Example image"
/>
</Section>
</Blocks>
)
).toStrictEqual([section]))
it('outputs section block with image accessories', () => {
for (const accessory of [
<Image src="https://example.com/image.jpg" alt="Example image" />,
<img src="https://example.com/image.jpg" alt="Example image" />,
]) {
expect(
JSXSlack(
<Blocks>
<Section blockId="with_image">
Image example
{accessory}
</Section>
</Blocks>
)
).toStrictEqual([section])
}
})

it('output section block with action accessories', () => {
for (const accessory of [
Expand Down Expand Up @@ -741,6 +744,10 @@ describe('jsx-slack', () => {
Hello! <b>World!</b>
<img src="https://example.com/test.jpg" alt="image" />
Image + Text
<Image
src="https://example.com/test2.jpg"
alt="image component"
/>
</Context>
</Blocks>
)
Expand All @@ -764,6 +771,11 @@ describe('jsx-slack', () => {
text: 'Image + Text',
verbatim: true,
},
{
type: 'image',
image_url: 'https://example.com/test2.jpg',
alt_text: 'image component',
},
],
},
]))
Expand Down

0 comments on commit 9575a92

Please sign in to comment.