Repository: speee/jsx-slack (ts)

Issue:
Allow `verbatim={boolean}` parameter 
For text objects, Slack allows a parameter `verbatim` to be passed, allowing some elements to be parsed by slack, without needing specific mrkdwn syntax (e.g. channels, users, urls). From Slack's doc on text object: https://api.slack.com/reference/block-kit/composition-objects#text


When set to false (as is default) URLs will be auto-converted into links, conversation names will be link-ified, and certain mentions will be automatically parsed. Using a value of true will skip any preprocessing of this nature, although you can still include manual parsing strings. This field is only usable when typeis mrkdwn.


It would be ideal to be able to use this attribute for components that support a text object (e.g. Section, Context, Fields (and pass them down to child elements). A specific use case where this would be ideal is rendering dynamic input in slack. If the dynamic content contains a URL, passing the text into a `jsx-slack` component such as a `<Button>` means you would first have to search for url's and wrap them with `<a>...</a>` to get them to render as links in Slack. Ideally you could opt into the `verbatim` parameter to simply pass the raw text to Slack to parse



Pull request description:
Recover for Mrkdwn component implementation
#97 was merged but looks like there is still incorrect behavior for `<Field>` component. A better auto-complete for REPL demo is lacked too.

This PR is recover pull request for #97. Close #73 again.

### ToDo

- [x] Add test case for `<Mrkdwn>` + `<Field>`
  - [x] Fix behavior
- [x] Update existing test case to use `toStrictEqual` rather than `toEqual`
- [x] Organize documentation
  - [x] Add use cases and preview link
  - [x] Match the tone of documentation into ours
  - [x] Be clearer the description of (confusable) `verbatim` prop
  - [x] Add `<Mrkdwn>` component to TOC of jsx-slack components
- [x] Support auto-completion in REPL demo
  - REPL has disabled JSX interpolation through `{}` by security reason, so it only supports to specify true with omitted value.
- [x] Refactor
  - [x] Refactor components to use `mrkdwn()` internal helper if possible
  - [x] Adopt symbol instead of string as jsx-slack internal node type (Prevent specifying internal object unexpectedly by user) 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bcf5c7d..ba5934d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,15 +2,15 @@
 
 ## [Unreleased]
 
-### Added
-
-- <Mrkdwn> component for use with <Section> and <Context> ([#73](https://github.com/speee/jsx-slack/issues/73), [#97](https://github.com/speee/jsx-slack/pull/97))
-
 ### Breaking
 
 - Components for [the outdated dialog](https://api.slack.com/dialogs) provided in `@speee-js/jsx-slack/dialog` can no longer use ([#84](https://github.com/speee/jsx-slack/pull/84))
 - Drop Node 8 support ([#100](https://github.com/speee/jsx-slack/pull/100))
 
+### Added
+
+- `<Mrkdwn>` text composition component ([#73](https://github.com/speee/jsx-slack/issues/73), [#97](https://github.com/speee/jsx-slack/pull/97) by [@javaPhil](https://github.com/javaPhil), [#103](https://github.com/speee/jsx-slack/pull/103))
+
 ### Fixed
 
 - Prevent over-escaping in valid emoji shorthand ([#98](https://github.com/speee/jsx-slack/issues/98), [#101](https://github.com/speee/jsx-slack/pull/101))
diff --git a/demo/schema.js b/demo/schema.js
index 10a7877..a52a741 100644
--- a/demo/schema.js
+++ b/demo/schema.js
@@ -120,6 +120,7 @@ const schema = {
     children: [
       'Field',
       'Image',
+      'Mrkdwn',
       'img',
       ...blockInteractiveComponents,
       ...markupHTML,
@@ -130,12 +131,13 @@ const schema = {
     children: [
       'Field',
       'Image',
+      'Mrkdwn',
       'img',
       ...blockInteractiveComponents,
       ...markupHTML,
     ],
   },
-  Field: { attrs: {}, children: markupHTML },
+  Field: { attrs: {}, children: ['Mrkdwn', ...markupHTML] },
   Divider: { attrs: blockCommonAttrs, children: [] },
   hr: { attrs: { id: null }, children: [] },
   Image: {
@@ -149,7 +151,7 @@ const schema = {
   Actions: { attrs: blockCommonAttrs, children: blockInteractiveComponents },
   Context: {
     attrs: blockCommonAttrs,
-    children: ['Image', 'img', 'span', ...markupHTML],
+    children: ['Image', 'Mrkdwn', 'img', 'span', ...markupHTML],
   },
   File: {
     attrs: { externalId: null, source: ['remote'], ...blockCommonAttrs },
@@ -315,6 +317,10 @@ const schema = {
   // Composition objects
   Confirm: {
     attrs: { title: null, confirm: null, deny: null },
+    children: ['Mrkdwn', ...markupHTML],
+  },
+  Mrkdwn: {
+    attrs: { verbatim: [] },
     children: markupHTML,
   },
 
diff --git a/docs/block-elements.md b/docs/block-elements.md
index 23c3dc8..4bbdc5c 100644
--- a/docs/block-elements.md
+++ b/docs/block-elements.md
@@ -501,23 +501,60 @@ You can use [HTML-like formatting](./html-like-formatting.md) to the content of
 - `confirm` (**required**): A text content of the button to confirm.
 - `deny` (**required**): A text content of the button to cancel.
 
-### <a name="mrkdwn_component" id="mrkdwn_component"></a> [`<Mrkdwn>`: Markdown Composition Component](https://api.slack.com/reference/block-kit/composition-objects#text)
+### <a name="mrkdwn" id="mrkdwn"></a> [`<Mrkdwn>`: Text composition object for `mrkdwn` type](https://api.slack.com/reference/block-kit/composition-objects#text)
 
-Mrkdwn is a text composition component is used when its needed to have a Text object and explicitly set the `verbatim` property. Setting `verbatim` to false will tell Slack to auto-convert links, conversaion names, and certain mentions to be linkified and automatically parsed. If `verbatim` set to true Slack will skip any prepreprocessing.
+`<Mrkdwn>`, is a component for text composition component, can use as a child of components which support HTML-like formatting. Typically it would be used when needed to set `verbatim` property explicitly.
 
-_Note: Slack recommends disabling automatic parsing on Text composition components and they have made it clear that they might deprecate this feature in the future. More information can be found <a href="https://api.slack.com/reference/surfaces/formatting#why_you_should_consider_disabling_automatic_parsing">here</a>_.
+Setting `verbatim` to `false` will tell Slack to auto-convert links, conversation names, and certain mentions to be linkified and automatically parsed. If `verbatim` set to true Slack will skip any preprocessing.
 
 ```jsx
 <Blocks>
+  {/* Section block */}
   <Section>
-    <Mrkdwn verbatim={false}>Hello @user!</Mrkdwn>
+    <Mrkdwn verbatim={false}>https://example.com/</Mrkdwn>
   </Section>
+
+  {/* Section block with fields */}
+  <Section>
+    <Field>
+      <Mrkdwn verbatim={false}>#general</Mrkdwn>
+    </Field>
+  </Section>
+
+  {/* Context block */}
+  <Context>
+    <Mrkdwn verbatim={false}>@here</Mrkdwn>
+    Hello!
+  </Context>
+
+  {/* Confirm composition object */}
+  <Actions>
+    <Button
+      confirm={
+        <Confirm title="Commit your action" confirm="Yes, please" deny="Cancel">
+          <Mrkdwn verbatim={false}>
+            <b>@foobar</b> Are you sure?
+          </Mrkdwn>
+        </Confirm>
+      }
+    >
+      Button
+    </Button>
+  </Actions>
 </Blocks>
 ```
 
-### Props
+[<img src="https://raw.githubusercontent.com/speee/jsx-slack/master/docs/preview-btn.svg?sanitize=true" width="240" />](https://api.slack.com/tools/block-kit-builder?mode=message&blocks=%5B%7B%22type%22%3A%22section%22%2C%22text%22%3A%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22https%3A%2F%2Fexample.com%2F%22%2C%22verbatim%22%3Afalse%7D%7D%2C%7B%22type%22%3A%22section%22%2C%22fields%22%3A%5B%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22%23general%22%2C%22verbatim%22%3Afalse%7D%5D%7D%2C%7B%22type%22%3A%22context%22%2C%22elements%22%3A%5B%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22%40here%22%2C%22verbatim%22%3Afalse%7D%2C%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22Hello!%22%2C%22verbatim%22%3Atrue%7D%5D%7D%2C%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%22Button%22%2C%22emoji%22%3Atrue%7D%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*%40here*%20Are%20you%20sure%3F%22%2C%22verbatim%22%3Afalse%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%7D%5D%7D%5D)
+
+#### Note
+
+_Slack recommends disabling automatic parsing on text composition components and they have made it clear that they might deprecate this feature in the future._ More information can be found [here](https://api.slack.com/reference/surfaces/formatting#why_you_should_consider_disabling_automatic_parsing).
+
+jsx-slack will disable automatic parsing by default even if you were not used `<Mrkdwn>` specifically. If possible, **we recommend never to use `<Mrkdwn>`** in Slack app created newly with jsx-slack.
+
+#### Props
 
-- verbatim: (optional): A boolean prop to specify whether or not Slack auto-convert links, conversaion names, and mentions.
+- `verbatim`: (optional): A boolean prop whether to disable automatic parsing for links, conversation names, and mentions by Slack.
 
 ## Input components for modal
 
diff --git a/docs/html-like-formatting.md b/docs/html-like-formatting.md
index 018766e..d3d50b1 100644
--- a/docs/html-like-formatting.md
+++ b/docs/html-like-formatting.md
@@ -71,7 +71,7 @@ The above would be replaced to just a plain text like this:
 
 ## Links
 
-jsx-slack will not recognize URL-like string as hyperlink. You should use `<a href="">` whenever you want to use a link.
+jsx-slack will not recognize URL-like string as hyperlink unless using [`<Mrkdwn verbatim={false}>`](block-elements.md#mrkdwn). Generally you should use `<a>` tag whenever you want to use a link.
 
 For example, `<a href="https://example.com/">Link</a>` will be converted to `<https://example.com/|Link>`, and rendered as like as "[Link](https://example.com)".
 
diff --git a/docs/jsx-components-for-block-kit.md b/docs/jsx-components-for-block-kit.md
index 2fe3633..b3359bb 100644
--- a/docs/jsx-components-for-block-kit.md
+++ b/docs/jsx-components-for-block-kit.md
@@ -41,6 +41,7 @@
 ### **[Composition objects](block-elements.md#composition-objects)**
 
 - [**`<Confirm>`**: Confirmation dialog](block-elements.md#confirm)
+- [**`<Mrkdwn>`**: Text composition object for `mrkdwn` type](block-elements.md#mrkdwn)
 
 ### **[Input components for modal](block-elements.md#input-components-for-modal)**
 
diff --git a/docs/layout-blocks.md b/docs/layout-blocks.md
index 67286b1..d0bb4ce 100644
--- a/docs/layout-blocks.md
+++ b/docs/layout-blocks.md
@@ -146,7 +146,7 @@ Display message context. It allows mixed contents consisted of texts and `<Image
 
 [<img src="https://raw.githubusercontent.com/speee/jsx-slack/master/docs/preview-btn.svg?sanitize=true" width="240" />](https://api.slack.com/tools/block-kit-builder?blocks=%5B%7B%22type%22%3A%22context%22%2C%22elements%22%3A%5B%7B%22type%22%3A%22image%22%2C%22image_url%22%3A%22https%3A%2F%2Fplacekitten.com%2F100%2F100%22%2C%22alt_text%22%3A%22Kitten%22%7D%2C%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22A%20kitten%20and%22%2C%22verbatim%22%3Atrue%7D%2C%7B%22type%22%3A%22image%22%2C%22image_url%22%3A%22https%3A%2F%2Fplacekitten.com%2F100%2F100%22%2C%22alt_text%22%3A%22Kitten%22%7D%2C%7B%22type%22%3A%22mrkdwn%22%2C%22text%22%3A%22more%20kitten.%22%2C%22verbatim%22%3Atrue%7D%5D%7D%5D)
 
-Text contents will merge in pertinent mrkdwn elements automatically, but they also may divide clearly by using `<span>` HTML intrinsic element.
+Text contents will merge in pertinent mrkdwn elements automatically, but they also may divide clearly by using `<span>` HTML intrinsic element (or [`<Mrkdwn>` component](block-elements.md#mrkdwn) for text composition object).
 
 ```jsx
 <Blocks>
diff --git a/src/block-kit/Context.tsx b/src/block-kit/Context.tsx
index f8cc755..a3dc400 100644
--- a/src/block-kit/Context.tsx
+++ b/src/block-kit/Context.tsx
@@ -3,6 +3,8 @@ import { ContextBlock, ImageElement, MrkdwnElement } from '@slack/types'
 import html from '../html'
 import { JSXSlack } from '../jsx'
 import { ObjectOutput } from '../utils'
+import { mrkdwnSymbol } from './composition/Mrkdwn'
+import { mrkdwn } from './composition/utils'
 import { BlockComponentProps } from './Blocks'
 
 type ContextElement = ImageElement | MrkdwnElement
@@ -22,8 +24,7 @@ export const Context: JSXSlack.FC<BlockComponentProps & {
       const { props } = child
 
       // <span> intrinsic HTML element
-      if (child.type === 'span')
-        return { type: 'mrkdwn' as const, text: html(child), verbatim: true }
+      if (child.type === 'span') return mrkdwn(html(child), true)
 
       // <img> intrinsic HTML element
       if (child.type === 'img')
@@ -33,31 +34,26 @@ export const Context: JSXSlack.FC<BlockComponentProps & {
           alt_text: props.alt,
         }
 
-      // A converted <Image> component
-      if (child.type === JSXSlack.NodeType.object && props.type === 'image')
-        return {
-          type: 'image' as const,
-          image_url: props.image_url,
-          alt_text: props.alt_text,
-        }
+      if (child.type === JSXSlack.NodeType.object) {
+        // A converted <Image> component
+        if (props.type === 'image')
+          return {
+            type: 'image' as const,
+            image_url: props.image_url,
+            alt_text: props.alt_text,
+          }
 
-      // A converted <MrkDwn> component
-      if (
-        child.type === JSXSlack.NodeType.object &&
-        props.type === 'mrkdwn_component'
-      )
-        return {
-          type: 'mrkdwn' as const,
-          text: props.text,
-          verbatim: props.verbatim,
-        }
+        // <MrkDwn> component
+        if (props.type === mrkdwnSymbol)
+          return mrkdwn(props.text, props.verbatim)
+      }
 
       return undefined
     })()
 
     if (current.length > 0 && (independentElement || child === endSymbol)) {
       // Text content
-      elements.push({ type: 'mrkdwn', text: html(current), verbatim: true })
+      elements.push(mrkdwn(html(current), true))
       current = []
     }
 
diff --git a/src/block-kit/Section.tsx b/src/block-kit/Section.tsx
index e22018e..9acaf14 100644
--- a/src/block-kit/Section.tsx
+++ b/src/block-kit/Section.tsx
@@ -5,9 +5,18 @@ import { JSXSlack } from '../jsx'
 import { ObjectOutput, aliasTo } from '../utils'
 import html from '../html'
 import { BlockComponentProps } from './Blocks'
-import { Image } from './Image'
+import { mrkdwnSymbol } from './composition/Mrkdwn'
+import { mrkdwn, mrkdwnFromNode } from './composition/utils'
 import { Button } from './elements/Button'
 import { Select } from './elements/Select'
+import { Image } from './Image'
+
+const fieldSymbol = Symbol('jsx-slack-field')
+
+interface FieldInternalObject {
+  type: typeof fieldSymbol
+  textElement: MrkdwnElement
+}
 
 export const sectionAccessoryTypes = [
   'image',
@@ -34,24 +43,21 @@ export const Section: JSXSlack.FC<BlockComponentProps & {
 
   let accessory: SectionBlock['accessory']
   let fields: SectionBlock['fields']
-  let text: MrkdwnElement | string | undefined
+  let text: MrkdwnElement | undefined
 
   for (const child of JSXSlack.normalizeChildren(children)) {
     let eaten = false
+
     if (typeof child === 'object') {
-      // Accessory, fields, and Mrkdwn
       if (child.type === JSXSlack.NodeType.object) {
+        // Accessory, fields, and Mrkdwn
         if (sectionAccessoryTypes.includes(child.props.type)) {
           accessory = JSXSlack(child)
-        } else if (child.props.type === 'mrkdwn') {
+        } else if (child.props.type === fieldSymbol) {
           if (!fields) fields = []
-          fields.push(child.props)
-        } else if (child.props.type === 'mrkdwn_component') {
-          text = {
-            type: 'mrkdwn',
-            text: child.props.text,
-            verbatim: child.props.verbatim,
-          }
+          fields.push(child.props.textElement)
+        } else if (child.props.type === mrkdwnSymbol) {
+          text = mrkdwn(child.props.text, child.props.verbatim)
         } else {
           throw new Error('<Section> has unexpected component as an accessory.')
         }
@@ -73,20 +79,16 @@ export const Section: JSXSlack.FC<BlockComponentProps & {
     if (!eaten) normalized.push(child)
   }
 
-  if (!text) text = html(normalized)
-
-  let sectionText
-  if (typeof text === 'object') {
-    sectionText = text
-  } else if (text && typeof text === 'string') {
-    sectionText = { text, type: 'mrkdwn', verbatim: true }
+  if (!text) {
+    const rendered = html(normalized)
+    if (rendered) text = mrkdwn(rendered, true)
   }
 
   return (
     <ObjectOutput<SectionBlock>
       type="section"
       block_id={id || blockId}
-      text={sectionText}
+      text={text}
       accessory={accessory}
       fields={fields}
     />
@@ -96,9 +98,8 @@ export const Section: JSXSlack.FC<BlockComponentProps & {
 export const Field: JSXSlack.FC<{
   children: JSXSlack.Children<{}>
 }> = ({ children }) => (
-  <ObjectOutput<MrkdwnElement>
-    type="mrkdwn"
-    text={html(children)}
-    verbatim={true}
+  <ObjectOutput<FieldInternalObject>
+    type={fieldSymbol}
+    textElement={mrkdwnFromNode(children)}
   />
 )
diff --git a/src/block-kit/composition/Confirm.tsx b/src/block-kit/composition/Confirm.tsx
index 394d28a..72eca18 100644
--- a/src/block-kit/composition/Confirm.tsx
+++ b/src/block-kit/composition/Confirm.tsx
@@ -1,9 +1,8 @@
 /** @jsx JSXSlack.h */
-import { Confirm as SlackConfirm, MrkdwnElement } from '@slack/types'
-import html from '../../html'
+import { Confirm as SlackConfirm } from '@slack/types'
 import { JSXSlack } from '../../jsx'
 import { ObjectOutput } from '../../utils'
-import { plainText, mrkdwn } from './utils'
+import { plainText, mrkdwnFromNode } from './utils'
 
 export interface ConfirmProps {
   children: JSXSlack.Children<{}>
@@ -12,25 +11,11 @@ export interface ConfirmProps {
   title: string
 }
 
-export const Confirm: JSXSlack.FC<ConfirmProps> = props => {
-  let confirmTextObject: string | MrkdwnElement = mrkdwn(html(props.children))
-
-  for (const child of JSXSlack.normalizeChildren(props.children)) {
-    if (typeof child === 'object' && child.props.type === 'mrkdwn_component') {
-      confirmTextObject = {
-        type: 'mrkdwn',
-        text: child.props.text,
-        verbatim: child.props.verbatim,
-      }
-    }
-  }
-
-  return (
-    <ObjectOutput<SlackConfirm>
-      title={plainText(props.title)}
-      text={confirmTextObject}
-      confirm={plainText(props.confirm)}
-      deny={plainText(props.deny)}
-    />
-  )
-}
+export const Confirm: JSXSlack.FC<ConfirmProps> = props => (
+  <ObjectOutput<SlackConfirm>
+    title={plainText(props.title)}
+    text={mrkdwnFromNode(props.children)}
+    confirm={plainText(props.confirm)}
+    deny={plainText(props.deny)}
+  />
+)
diff --git a/src/block-kit/composition/Mrkdwn.tsx b/src/block-kit/composition/Mrkdwn.tsx
index b379592..4fe89bd 100644
--- a/src/block-kit/composition/Mrkdwn.tsx
+++ b/src/block-kit/composition/Mrkdwn.tsx
@@ -3,23 +3,23 @@ import { JSXSlack } from '../../jsx'
 import { ObjectOutput } from '../../utils'
 import html from '../../html'
 
+export const mrkdwnSymbol = Symbol('jsx-slack-mrkdwn-composition')
+
 interface MrkdwnProps {
   children: JSXSlack.Children<{}>
   verbatim?: boolean
 }
 
 interface MrkdwnComponentProps {
-  type: 'mrkdwn_component'
+  type: typeof mrkdwnSymbol
   text: string
   verbatim?: boolean
 }
 
-export const Mrkdwn: JSXSlack.FC<MrkdwnProps> = ({ children, verbatim }) => {
-  return (
-    <ObjectOutput<MrkdwnComponentProps>
-      type="mrkdwn_component"
-      text={html(children)}
-      verbatim={verbatim}
-    />
-  )
-}
+export const Mrkdwn: JSXSlack.FC<MrkdwnProps> = ({ children, verbatim }) => (
+  <ObjectOutput<MrkdwnComponentProps>
+    type={mrkdwnSymbol}
+    text={html(children)}
+    verbatim={verbatim}
+  />
+)
diff --git a/src/block-kit/composition/utils.ts b/src/block-kit/composition/utils.ts
index 6a3b471..4fc8aa4 100644
--- a/src/block-kit/composition/utils.ts
+++ b/src/block-kit/composition/utils.ts
@@ -1,4 +1,7 @@
 import { MrkdwnElement, PlainTextElement } from '@slack/types'
+import html from '../../html'
+import { JSXSlack } from '../../jsx'
+import { mrkdwnSymbol } from './Mrkdwn'
 
 export const plainText = (
   text: string,
@@ -9,8 +12,20 @@ export const plainText = (
   emoji: !!opts.emoji,
 })
 
-export const mrkdwn = (mrkdwnText: string): MrkdwnElement => ({
+export const mrkdwn = (
+  mrkdwnText: string,
+  verbatim?: boolean
+): MrkdwnElement => ({
   type: 'mrkdwn',
   text: mrkdwnText,
-  verbatim: true,
+  verbatim,
 })
+
+export const mrkdwnFromNode = (node: JSXSlack.Children<{}>): MrkdwnElement => {
+  const [child] = JSXSlack.normalizeChildren(node)
+
+  if (typeof child === 'object' && child.props.type === mrkdwnSymbol)
+    return mrkdwn(child.props.text, child.props.verbatim)
+
+  return mrkdwn(html(node), true)
+}


Test patch:
diff --git a/test/block-kit/block-elements/composition-objects.tsx b/test/block-kit/block-elements/composition-objects.tsx
index 295385f..daf7444 100644
--- a/test/block-kit/block-elements/composition-objects.tsx
+++ b/test/block-kit/block-elements/composition-objects.tsx
@@ -8,6 +8,7 @@ import JSXSlack, {
   Mrkdwn,
   Section,
   Context,
+  Field,
 } from '../../../src/index'
 
 beforeEach(() => JSXSlack.exactMode(false))
@@ -75,7 +76,8 @@ describe('Composition objects', () => {
           },
         ]
       `))
-    it('outputs action included <Confirm> object with a <Mrkdwn> child', () => {
+
+    it('outputs action included <Confirm> object with a <Mrkdwn> child', () =>
       expect(
         JSXSlack(
           <Blocks>
@@ -87,7 +89,9 @@ describe('Composition objects', () => {
                     confirm="Yes, please"
                     deny="Cancel"
                   >
-                    <Mrkdwn verbatim={false}>submit @user</Mrkdwn>
+                    <Mrkdwn verbatim={false}>
+                      <b>Are you sure?</b> Message will be share.
+                    </Mrkdwn>
                   </Confirm>
                 }
               >
@@ -96,123 +100,143 @@ describe('Composition objects', () => {
             </Actions>
           </Blocks>
         )
-      ).toEqual([
-        {
-          block_id: 'actions',
-          elements: [
-            {
-              confirm: {
-                confirm: {
-                  emoji: true,
-                  text: 'Yes, please',
-                  type: 'plain_text',
-                },
-                deny: {
-                  emoji: true,
-                  text: 'Cancel',
-                  type: 'plain_text',
-                },
-                text: {
-                  text: 'submit @user',
-                  type: 'mrkdwn',
-                  verbatim: false,
+      ).toMatchInlineSnapshot(`
+        Array [
+          Object {
+            "block_id": "actions",
+            "elements": Array [
+              Object {
+                "confirm": Object {
+                  "confirm": Object {
+                    "emoji": true,
+                    "text": "Yes, please",
+                    "type": "plain_text",
+                  },
+                  "deny": Object {
+                    "emoji": true,
+                    "text": "Cancel",
+                    "type": "plain_text",
+                  },
+                  "text": Object {
+                    "text": "*Are you sure?* Message will be share.",
+                    "type": "mrkdwn",
+                    "verbatim": false,
+                  },
+                  "title": Object {
+                    "emoji": true,
+                    "text": "Share to SNS",
+                    "type": "plain_text",
+                  },
                 },
-                title: {
-                  emoji: true,
-                  text: 'Share to SNS',
-                  type: 'plain_text',
+                "text": Object {
+                  "emoji": true,
+                  "text": "Share",
+                  "type": "plain_text",
                 },
+                "type": "button",
               },
-              text: {
-                emoji: true,
-                text: 'Share',
-                type: 'plain_text',
-              },
-              type: 'button',
-            },
-          ],
-          type: 'actions',
+            ],
+            "type": "actions",
+          },
+        ]
+      `))
+  })
+
+  describe('<Mrkdwn>', () => {
+    it('outputs a <Section> block with a <Mrkdwn> component and preserves the verbatim prop', () => {
+      expect(
+        JSXSlack(
+          <Blocks>
+            <Section>
+              <Mrkdwn verbatim={false}>Hello!</Mrkdwn>
+            </Section>
+          </Blocks>
+        )
+      ).toStrictEqual([
+        {
+          type: 'section',
+          text: { type: 'mrkdwn', text: 'Hello!', verbatim: false },
         },
       ])
-    })
-    describe('<Mrkdwn>', () => {
-      it('outputs a <Section> block with a <Mrkdwn> component and preserves the verbatim prop', () => {
-        expect(
-          JSXSlack(
-            <Blocks>
-              <Section>
+
+      expect(
+        JSXSlack(
+          <Blocks>
+            <Section>
+              <Field>
                 <Mrkdwn verbatim={false}>Hello!</Mrkdwn>
-              </Section>
-            </Blocks>
-          )
-        ).toEqual([
-          {
-            type: 'section',
-            text: { type: 'mrkdwn', text: 'Hello!', verbatim: false },
-          },
-        ])
-      })
-      it('outputs a <Context> block with an image and multiple mrkdwn elements', () => {
-        expect(
-          JSXSlack(
-            <Blocks>
-              <Context>
-                <Image src="https://example.com/test.jpg" alt="Test Image" />
-                Supporting <code>context</code> block would be hard!
-                <Mrkdwn verbatim={false}>
-                  <i>@here</i>
-                </Mrkdwn>
-                :dizzy_face:
-              </Context>
-            </Blocks>
-          )
-        ).toEqual([
-          {
-            type: 'context',
-            elements: [
-              {
-                type: 'image',
-                image_url: 'https://example.com/test.jpg',
-                alt_text: 'Test Image',
-              },
-              {
-                type: 'mrkdwn',
-                text: 'Supporting `context` block would be hard!',
-                verbatim: true,
-              },
-              {
-                type: 'mrkdwn',
-                text: '_@here_',
-                verbatim: false,
-              },
-              {
-                type: 'mrkdwn',
-                text: ':dizzy_face:',
-                verbatim: true,
-              },
-            ],
-          },
-        ])
-      })
-      it('converts <Mrkdwn> elements into mrkdwn elements and preserves the verbatim prop', () =>
-        expect(
-          JSXSlack(
-            <Blocks>
-              <Context>
-                <Mrkdwn verbatim={false}>Hello</Mrkdwn>
-                World
-              </Context>
-            </Blocks>
-          )
-        ).toEqual([
-          {
-            type: 'context',
-            elements: [
-              { type: 'mrkdwn', text: 'Hello', verbatim: false },
-              { type: 'mrkdwn', text: 'World', verbatim: true },
-            ],
-          },
-        ]))
+              </Field>
+            </Section>
+          </Blocks>
+        )
+      ).toStrictEqual([
+        {
+          type: 'section',
+          fields: [{ type: 'mrkdwn', text: 'Hello!', verbatim: false }],
+        },
+      ])
     })
+
+    it('outputs a <Context> block with an image and multiple mrkdwn elements', () =>
+      expect(
+        JSXSlack(
+          <Blocks>
+            <Context>
+              <Image src="https://example.com/test.jpg" alt="Test Image" />
+              Supporting <code>context</code> block would be hard!
+              <Mrkdwn verbatim={false}>
+                <i>@here</i>
+              </Mrkdwn>
+              :dizzy_face:
+            </Context>
+          </Blocks>
+        )
+      ).toStrictEqual([
+        {
+          type: 'context',
+          elements: [
+            {
+              type: 'image',
+              image_url: 'https://example.com/test.jpg',
+              alt_text: 'Test Image',
+            },
+            {
+              type: 'mrkdwn',
+              text: 'Supporting `context` block would be hard!',
+              verbatim: true,
+            },
+            {
+              type: 'mrkdwn',
+              text: '_@here_',
+              verbatim: false,
+            },
+            {
+              type: 'mrkdwn',
+              text: ':dizzy_face:',
+              verbatim: true,
+            },
+          ],
+        },
+      ]))
+
+    it('converts <Mrkdwn> elements into mrkdwn elements and preserves the verbatim prop', () =>
+      expect(
+        JSXSlack(
+          <Blocks>
+            <Context>
+              <Mrkdwn verbatim={false}>Hello</Mrkdwn>
+              World
+            </Context>
+          </Blocks>
+        )
+      ).toStrictEqual([
+        {
+          type: 'context',
+          elements: [
+            { type: 'mrkdwn', text: 'Hello', verbatim: false },
+            { type: 'mrkdwn', text: 'World', verbatim: true },
+          ],
+        },
+      ]))
   })
 })