@ndlib/component-library 0.0.101 → 0.0.103
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.
- package/dist/components/elements/Icon/Icon.test.js +8 -0
- package/dist/components/elements/Icon/index.js +1 -1
- package/dist/components/elements/Markdown/Markdown.stories.d.ts +0 -1
- package/dist/components/elements/Markdown/Markdown.stories.js +19 -21
- package/dist/components/elements/Markdown/Markdown.test.js +11 -8
- package/dist/components/elements/Markdown/index.d.ts +0 -4
- package/dist/components/elements/Markdown/index.js +32 -4
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { render } from '../../../utils/test';
|
|
|
3
3
|
import { Icon } from '.';
|
|
4
4
|
import { SPACING } from '../../../theme';
|
|
5
5
|
import { FONT_SIZE, fontSizeMap } from '../../../theme/typography';
|
|
6
|
+
import { vitest } from 'vitest';
|
|
6
7
|
const MockIcon = () => {
|
|
7
8
|
return _jsx("div", { children: "Mock Icon" });
|
|
8
9
|
};
|
|
@@ -23,4 +24,11 @@ describe('Icon', () => {
|
|
|
23
24
|
padding: SPACING[1],
|
|
24
25
|
});
|
|
25
26
|
});
|
|
27
|
+
it('icon can be clicked', () => {
|
|
28
|
+
const onClick = vitest.fn();
|
|
29
|
+
const { getByLabelText } = render(_jsx(Icon, { icon: MockIcon, sx: { p: 1 }, onClick: onClick, "aria-label": "My Icon" }));
|
|
30
|
+
const icon = getByLabelText('My Icon');
|
|
31
|
+
icon.click();
|
|
32
|
+
expect(onClick).toHaveBeenCalled();
|
|
33
|
+
});
|
|
26
34
|
});
|
|
@@ -20,7 +20,7 @@ export const Icon = (_a) => {
|
|
|
20
20
|
if (onClick && !rest['aria-label']) {
|
|
21
21
|
flagInDevelopment('Icon component with onClick should have an aria-label and tabIndex={0}');
|
|
22
22
|
}
|
|
23
|
-
return (_jsx("div", Object.assign({ tabIndex: onClick ? 0 : undefined, role: onClick ? 'button' : 'none', sx: Object.assign(Object.assign({}, sx), { fontSize: size, display: 'flex', alignItems: 'center', justifyContent: 'center', ':hover': onClick
|
|
23
|
+
return (_jsx("div", Object.assign({ tabIndex: onClick ? 0 : undefined, role: onClick ? 'button' : 'none', onClick: onClick, sx: Object.assign(Object.assign({}, sx), { fontSize: size, display: 'flex', alignItems: 'center', justifyContent: 'center', ':hover': onClick
|
|
24
24
|
? {
|
|
25
25
|
cursor: 'pointer',
|
|
26
26
|
transform: 'scale(1.05)',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Markdown } from '.';
|
|
3
3
|
import { FONT_WEIGHT } from '../../../theme/typography';
|
|
4
4
|
import { COLOR } from '../../../theme/colors';
|
|
5
5
|
const meta = {
|
|
@@ -15,7 +15,6 @@ litora tellus ligula porttitor metus.
|
|
|
15
15
|
`;
|
|
16
16
|
export default meta;
|
|
17
17
|
const startingContent = `
|
|
18
|
-
|
|
19
18
|
# Inline styles
|
|
20
19
|
This paragraph has __bold content__ and **more bold content** and _italic content_ and *more italic content*
|
|
21
20
|
|
|
@@ -59,6 +58,14 @@ reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
|
|
59
58
|
nulla pariatur.
|
|
60
59
|
|
|
61
60
|
https://this-should-be-auto-linked.nd.edu
|
|
61
|
+
|
|
62
|
+
While Gura says that the exhibit was inspired by the themes of the Medieval conference and will appeal to its attendees, the displays are curated to interest Notre Dame students and faculty across various disciplines, as well as the general public.
|
|
63
|
+
|
|
64
|
+
“I'm trying to pick items to tell a story that viewers can appreciate on different levels at the same time,” he said.
|
|
65
|
+
|
|
66
|
+
To tell that story, Gura decided to give each of the seven cases housing this exhibit a theme.
|
|
67
|
+
|
|
68
|
+
> “I think it's an exciting way to create a journey through time and space using the objects themselves as the primary storyteller,” he said. “They will drive the narrative from case to case. You can be exposed to different things that the average person never really thought about.”
|
|
62
69
|
`;
|
|
63
70
|
export const Default = {
|
|
64
71
|
render: (args) => _jsx(Markdown, Object.assign({}, args)),
|
|
@@ -67,14 +74,16 @@ export const Default = {
|
|
|
67
74
|
},
|
|
68
75
|
};
|
|
69
76
|
const htmlContent = `
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
## HTML Content
|
|
78
|
+
<p style='color: red;'>hello world </p>
|
|
79
|
+
> test
|
|
80
|
+
<img
|
|
81
|
+
style="width: 300px"
|
|
82
|
+
src="https://s3.amazonaws.com/resources.library.nd.edu/images/website/search.banner.fall.jpg"
|
|
83
|
+
></img>
|
|
84
|
+
<a href="https://google.com" class="embedly-card" data-card-width="100px" data-card-controls="0">Embedded content: https://google.com</a>
|
|
85
|
+
<iframe src="https://www.facebook.com/plugins/video.php?href=https%3A%2F%2Fwww.facebook.com%2FNDLibraries%2Fvideos%2F1673794309311939%2F&show_text=0&width=560" width="560" height="315" style="border:none;overflow:hidden" scrolling="no" frameborder="0" ></iframe>
|
|
86
|
+
${startingContent}
|
|
78
87
|
`;
|
|
79
88
|
export const WithHtml = {
|
|
80
89
|
render: (args) => _jsx(Markdown, Object.assign({}, args)),
|
|
@@ -102,17 +111,6 @@ export const CustomizeStyles = {
|
|
|
102
111
|
content: startingContent,
|
|
103
112
|
},
|
|
104
113
|
};
|
|
105
|
-
export const CustomHtmlSanitize = {
|
|
106
|
-
render: (args) => _jsx(Markdown, Object.assign({}, args)),
|
|
107
|
-
args: {
|
|
108
|
-
enableHtml: true,
|
|
109
|
-
sanitizeHtmlOptions: {
|
|
110
|
-
allowedAttributes: Object.assign(Object.assign({}, DEFAULT_ALLOWED_ATTRIBUTES), { p: ['style'], img: ['src', 'style'] }),
|
|
111
|
-
allowedTags: [...DEFAULT_ALLOWED_TAGS, 'img'],
|
|
112
|
-
},
|
|
113
|
-
content: htmlContent,
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
114
|
export const NoHtml = {
|
|
117
115
|
render: (args) => _jsx(Markdown, Object.assign({}, args)),
|
|
118
116
|
args: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { render } from '../../../utils/test';
|
|
3
|
-
import {
|
|
3
|
+
import { Markdown } from '.';
|
|
4
4
|
const testMarkdown = `
|
|
5
5
|
# Inline styles
|
|
6
6
|
This paragraph has __bold content__ and **more bold content** and _italic content_ and *more italic content*
|
|
@@ -37,6 +37,14 @@ reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
|
|
37
37
|
nulla pariatur.
|
|
38
38
|
|
|
39
39
|
https://this-should-be-auto-linked.nd.edu
|
|
40
|
+
|
|
41
|
+
While Gura says that the exhibit was inspired by the themes of the Medieval conference and will appeal to its attendees, the displays are curated to interest Notre Dame students and faculty across various disciplines, as well as the general public.
|
|
42
|
+
|
|
43
|
+
“I'm trying to pick items to tell a story that viewers can appreciate on different levels at the same time,” he said.
|
|
44
|
+
|
|
45
|
+
To tell that story, Gura decided to give each of the seven cases housing this exhibit a theme.
|
|
46
|
+
|
|
47
|
+
> “I think it's an exciting way to create a journey through time and space using the objects themselves as the primary storyteller,” he said. “They will drive the narrative from case to case. You can be exposed to different things that the average person never really thought about.”
|
|
40
48
|
`;
|
|
41
49
|
const htmlMarkdown = `
|
|
42
50
|
## HTML Content
|
|
@@ -46,6 +54,7 @@ const htmlMarkdown = `
|
|
|
46
54
|
<a href="https://google.com" class="embedly-card" data-card-width="100px" data-card-controls="0">Embedded content: https://google.com</a>
|
|
47
55
|
<iframe src="https://www.facebook.com/plugins/video.php?href=https%3A%2F%2Fwww.facebook.com%2FNDLibraries%2Fvideos%2F1673794309311939%2F&show_text=0&width=560" width="560" height="315" style="border:none;overflow:hidden" scrolling="no" frameborder="0"></iframe>
|
|
48
56
|
<img href="https://google.com"></img>
|
|
57
|
+
${testMarkdown}
|
|
49
58
|
`;
|
|
50
59
|
describe('Markdown', () => {
|
|
51
60
|
it('renders alert content', () => {
|
|
@@ -87,7 +96,7 @@ describe('Markdown', () => {
|
|
|
87
96
|
expect(getAllByRole('link')).toBeDefined();
|
|
88
97
|
expect(() => getByText(' ')).toThrow();
|
|
89
98
|
expect(container.getElementsByTagName('script')).toHaveLength(0);
|
|
90
|
-
expect(container.getElementsByTagName('img')).toHaveLength(
|
|
99
|
+
expect(container.getElementsByTagName('img')).toHaveLength(2);
|
|
91
100
|
expect(container.getElementsByTagName('iframe')).toHaveLength(1);
|
|
92
101
|
});
|
|
93
102
|
it('does not render html when disabled', () => {
|
|
@@ -96,10 +105,4 @@ describe('Markdown', () => {
|
|
|
96
105
|
expect(container.getElementsByTagName('script')).toHaveLength(0);
|
|
97
106
|
expect(container.getElementsByTagName('iframe')).toHaveLength(0);
|
|
98
107
|
});
|
|
99
|
-
it('supports customizing html sanitization', () => {
|
|
100
|
-
const { container } = render(_jsx(Markdown, { content: htmlMarkdown, enableHtml: true, sanitizeHtmlOptions: {
|
|
101
|
-
allowedTags: DEFAULT_ALLOWED_TAGS.concat(['img']),
|
|
102
|
-
} }));
|
|
103
|
-
expect(container.getElementsByTagName('img')).toHaveLength(1);
|
|
104
|
-
});
|
|
105
108
|
});
|
|
@@ -11,10 +11,6 @@ type MarkdownProps = StyledElementProps<HTMLDivElement, {
|
|
|
11
11
|
enableHtml?: boolean;
|
|
12
12
|
imageStyles?: React.CSSProperties;
|
|
13
13
|
headingLevelOffset?: number;
|
|
14
|
-
sanitizeHtmlOptions?: {
|
|
15
|
-
allowedTags?: string[];
|
|
16
|
-
allowedAttributes?: sanitizeHtml.IOptions['allowedAttributes'];
|
|
17
|
-
};
|
|
18
14
|
customStyles?: Record<string, StylesProp>;
|
|
19
15
|
}>;
|
|
20
16
|
export declare const Markdown: React.FC<MarkdownProps>;
|
|
@@ -22,24 +22,52 @@ import remarkGfm from 'remark-gfm';
|
|
|
22
22
|
import { BlockQuote } from '../BlockQuote';
|
|
23
23
|
export const DEFAULT_ALLOWED_TAGS = sanitizeHtml.defaults.allowedTags.concat([
|
|
24
24
|
'iframe',
|
|
25
|
+
'img',
|
|
25
26
|
]);
|
|
26
27
|
export const DEFAULT_ALLOWED_ATTRIBUTES = Object.assign(Object.assign({}, sanitizeHtml.defaults.allowedAttributes), { iframe: ['*'], a: sanitizeHtml.defaults.allowedAttributes.a.concat([
|
|
27
28
|
'class',
|
|
28
29
|
'data-card-width',
|
|
29
30
|
'data-card-controls',
|
|
30
31
|
]) });
|
|
32
|
+
const parseBlockquotes = (content) => {
|
|
33
|
+
const contentArray = content.split('\n');
|
|
34
|
+
const newContent = [];
|
|
35
|
+
let isAddingBlockquote = false;
|
|
36
|
+
for (const line of contentArray) {
|
|
37
|
+
if (line.startsWith('> ') && !isAddingBlockquote) {
|
|
38
|
+
const newLine = line.replace('> ', '');
|
|
39
|
+
newContent.push(`<blockquote>${newLine}`);
|
|
40
|
+
isAddingBlockquote = true;
|
|
41
|
+
}
|
|
42
|
+
else if (line.startsWith('> ') && isAddingBlockquote) {
|
|
43
|
+
newContent.push(line.replace('> ', ''));
|
|
44
|
+
}
|
|
45
|
+
else if (isAddingBlockquote) {
|
|
46
|
+
newContent.push(`</blockquote>\n\n${line}`);
|
|
47
|
+
isAddingBlockquote = false;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
newContent.push(line);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (isAddingBlockquote) {
|
|
54
|
+
newContent.push('</blockquote>');
|
|
55
|
+
}
|
|
56
|
+
return newContent.join('\n');
|
|
57
|
+
};
|
|
31
58
|
const dynamicTopMarginStyles = {
|
|
32
59
|
[firstChildAltSelector]: {
|
|
33
60
|
mt: 0,
|
|
34
61
|
},
|
|
35
62
|
};
|
|
36
63
|
export const Markdown = (_a) => {
|
|
37
|
-
var { content, enableHtml,
|
|
64
|
+
var { content, enableHtml, imageStyles, customStyles = {}, headingLevelOffset = 1 } = _a, rest = __rest(_a, ["content", "enableHtml", "imageStyles", "customStyles", "headingLevelOffset"]);
|
|
38
65
|
let sanitizedContent = content;
|
|
39
66
|
if (enableHtml) {
|
|
40
|
-
sanitizedContent =
|
|
41
|
-
|
|
42
|
-
|
|
67
|
+
sanitizedContent = parseBlockquotes(content);
|
|
68
|
+
sanitizedContent = sanitizeHtml(sanitizedContent, {
|
|
69
|
+
allowedTags: DEFAULT_ALLOWED_TAGS,
|
|
70
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES,
|
|
43
71
|
});
|
|
44
72
|
}
|
|
45
73
|
return (_jsx("div", Object.assign({}, rest, { children: _jsx(ReactMarkdown, Object.assign({ rehypePlugins: enableHtml ? [rehypeRaw, remarkGfm] : [remarkGfm], components: {
|