Skip to content
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

Allow Banners to render basic markdown such as links and emphasis. #3481

Merged
merged 4 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
of any `Panel`.
* Added new `Panel.headerClassName` prop for straightforward CSS manipulation of panel's header.
* Improved styling for disabled `checkbox` inputs.
* Added new `Markdown` component for rendering Markdown formatted strings as markup. This includes
bundling `react-markdown` in Hoist. If your app already uses `react-markdown` or similar, you should
move to use the new `Markdown` component to benefit from future upgrades.
* Enabled Banners to render bold, italics and links using Markdown syntax.

### 📚 Libraries

* react-markdown `8.0.7`
* remark-breaks `3.0.3`

## 59.0.3 - 2023-08-25

Expand Down
32 changes: 32 additions & 0 deletions cmp/markdown/Markdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | [email protected])
*
* Copyright © 2023 Extremely Heavy Industries Inc.
*/
import {hoistCmp, HoistProps} from '@xh/hoist/core';
import {reactMarkdown} from '@xh/hoist/kit/react-markdown';
import remarkBreaks from 'remark-breaks';

interface MarkdownProps extends HoistProps {
/**
* Markdown formatted string to render.
*/
content: string;

/** True (default) to render new lines with <br/> tags. */
lineBreaks?: boolean;
}

/**
* Render Markdown formatted strings as HTML (e.g. **foo** becomes <strong>foo</strong>).
*/
export const [Markdown, markdown] = hoistCmp.withFactory<MarkdownProps>({
displayName: 'Markdown',
render({content, lineBreaks = true}) {
return reactMarkdown({
item: content,
remarkPlugins: lineBreaks ? [remarkBreaks] : null
});
}
});
1 change: 1 addition & 0 deletions cmp/markdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Markdown';
25 changes: 25 additions & 0 deletions desktop/appcontainer/Banner.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@ body.xh-app .xh-banner {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

// Disallow most markdown styling except **bold**, *italics* and (links)
h1,
h2,
h3,
h4,
p,
ul,
li,
a,
code {
display: inline;
margin: unset;
padding: unset;
color: unset;
font-weight: unset;
font-size: unset;
font-family: unset;
list-style: none;
}

// Render links with an underline
a {
text-decoration: underline;
}
}

&__action-button,
Expand Down
3 changes: 2 additions & 1 deletion desktop/appcontainer/Banner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {hframe, div} from '@xh/hoist/cmp/layout';
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
import {button} from '@xh/hoist/desktop/cmp/button';
import {Icon} from '@xh/hoist/icon';
import {markdown} from '@xh/hoist/cmp/markdown';
import {isFunction, isEmpty} from 'lodash';
import classNames from 'classnames';

Expand Down Expand Up @@ -43,7 +44,7 @@ export const banner = hoistCmp.factory({
icon,
div({
className: 'xh-banner__message',
item: message,
item: markdown({content: message}),
onClick
})
]
Expand Down
11 changes: 11 additions & 0 deletions kit/react-markdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | [email protected])
*
* Copyright © 2023 Extremely Heavy Industries Inc.
*/
import {elementFactory} from '@xh/hoist/core';
import ReactMarkdown from 'react-markdown';

export {ReactMarkdown};
export const reactMarkdown = elementFactory(ReactMarkdown);
25 changes: 25 additions & 0 deletions mobile/appcontainer/Banner.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@ body.xh-app .xh-banner {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

// Disallow most markdown styling except **bold**, *italics* and (links)
h1,
h2,
h3,
h4,
p,
ul,
li,
a,
code {
display: inline;
margin: unset;
padding: unset;
color: unset;
font-weight: unset;
font-size: unset;
font-family: unset;
list-style: none;
}

// Render links with an underline
a {
text-decoration: underline;
}
}

&__action-button {
Expand Down
3 changes: 2 additions & 1 deletion mobile/appcontainer/Banner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {XH, uses, hoistCmp} from '@xh/hoist/core';
import {hframe, div} from '@xh/hoist/cmp/layout';
import {button} from '@xh/hoist/mobile/cmp/button';
import {Icon} from '@xh/hoist/icon';
import {markdown} from '@xh/hoist/cmp/markdown';
import {isEmpty, isFunction} from 'lodash';
import classNames from 'classnames';

Expand Down Expand Up @@ -41,7 +42,7 @@ export const banner = hoistCmp.factory({
icon,
div({
className: 'xh-banner__message',
item: message,
item: markdown({content: message}),
onClick
})
]
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@
"react-dates": "~21.8.0",
"react-dropzone": "~10.2.2",
"react-grid-layout": "^1.3.4",
"react-markdown": "^8.0.7",
"react-onsenui": "~1.13.2",
"react-popper": "~2.3.0",
"react-select": "~4.3.1",
"react-transition-group": "~4.4.2",
"react-windowed-select": "~3.1.2",
"regenerator-runtime": "~0.13.11",
"remark-breaks": "^3.0.3",
"resize-observer-polyfill": "~1.5.1",
"router5": "~7.0.2",
"router5-plugin-browser": "~7.0.2",
Expand Down
4 changes: 2 additions & 2 deletions svc/AlertBannerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Copyright © 2023 Extremely Heavy Industries Inc.
*/
import {BannerModel} from '@xh/hoist/appcontainer/BannerModel';
import {div, p} from '@xh/hoist/cmp/layout';
import {markdown} from '@xh/hoist/cmp/markdown';
import {BannerSpec, HoistService, Intent, managed, XH} from '@xh/hoist/core';
import {Icon} from '@xh/hoist/icon';
import {Timer} from '@xh/hoist/utils/async';
Expand Down Expand Up @@ -78,7 +78,7 @@ export class AlertBannerService extends HoistService {
XH.alert({
title: 'Alert',
icon,
message: div(msgLines.map(it => p(it)))
message: markdown({content: message})
});

let actionButtonProps, onClick;
Expand Down
Loading