@apify/ui-library 0.71.1-featcolortokens-178953.56 → 0.71.1-featcolortokens-178953.63
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/src/design_system/colors/generated/{dark.d.ts → css_variables.dark.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.dark.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/{dark.js → css_variables.dark.js} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.dark.js.map +1 -0
- package/dist/src/design_system/colors/generated/{light.d.ts → css_variables.light.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.light.d.ts.map +1 -0
- package/{src/design_system/colors/generated/light.ts → dist/src/design_system/colors/generated/css_variables.light.js} +1 -1
- package/dist/src/design_system/colors/generated/css_variables.light.js.map +1 -0
- package/dist/src/design_system/colors/generated/{palette.dark.d.ts → css_variables_palette.dark.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.dark.d.ts.map +1 -0
- package/dist/src/design_system/colors/generated/{palette.dark.js → css_variables_palette.dark.js} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.dark.js.map +1 -0
- package/dist/src/design_system/colors/generated/{palette.light.d.ts → css_variables_palette.light.d.ts} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.light.d.ts.map +1 -0
- package/{src/design_system/colors/generated/palette.light.ts → dist/src/design_system/colors/generated/css_variables_palette.light.js} +1 -1
- package/dist/src/design_system/colors/generated/css_variables_palette.light.js.map +1 -0
- package/dist/src/design_system/colors/index.d.ts +4 -4
- package/dist/src/design_system/colors/index.d.ts.map +1 -1
- package/dist/src/design_system/colors/index.js +4 -4
- package/dist/src/design_system/colors/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +7 -5
- package/.stylelintrc +0 -12
- package/CHANGELOG.md +0 -3334
- package/CODEOWNERS +0 -7
- package/dist/src/design_system/colors/generated/dark.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/dark.js.map +0 -1
- package/dist/src/design_system/colors/generated/light.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/light.js +0 -147
- package/dist/src/design_system/colors/generated/light.js.map +0 -1
- package/dist/src/design_system/colors/generated/palette.dark.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/palette.dark.js.map +0 -1
- package/dist/src/design_system/colors/generated/palette.light.d.ts.map +0 -1
- package/dist/src/design_system/colors/generated/palette.light.js +0 -74
- package/dist/src/design_system/colors/generated/palette.light.js.map +0 -1
- package/dist/src/design_system/colors_theme.d.ts +0 -213
- package/dist/src/design_system/colors_theme.d.ts.map +0 -1
- package/dist/src/design_system/colors_theme.js +0 -213
- package/dist/src/design_system/colors_theme.js.map +0 -1
- package/dist/src/design_system/properties_theme.d.ts +0 -175
- package/dist/src/design_system/properties_theme.d.ts.map +0 -1
- package/dist/src/design_system/properties_theme.js +0 -315
- package/dist/src/design_system/properties_theme.js.map +0 -1
- package/eslint.config.mjs +0 -44
- package/src/codemods/generate_typograpy_tokens_files.mjs +0 -137
- package/src/components/action_link.tsx +0 -60
- package/src/components/actor_template_card.tsx +0 -116
- package/src/components/badge.tsx +0 -148
- package/src/components/banner.tsx +0 -94
- package/src/components/blog_article.tsx +0 -85
- package/src/components/box.tsx +0 -127
- package/src/components/button.tsx +0 -305
- package/src/components/chip.tsx +0 -128
- package/src/components/code/action_button.tsx +0 -96
- package/src/components/code/code_block/code_block.styled.tsx +0 -180
- package/src/components/code/code_block/code_block.tsx +0 -224
- package/src/components/code/code_block/code_block_with_tabs.tsx +0 -257
- package/src/components/code/code_block/utils.tsx +0 -67
- package/src/components/code/index.ts +0 -5
- package/src/components/code/inline_code/inline_code.tsx +0 -62
- package/src/components/code/one_line_code/one_line_code.tsx +0 -228
- package/src/components/code/prism_highlighter.tsx +0 -180
- package/src/components/color_wheel_gradient.tsx +0 -31
- package/src/components/floating/index.ts +0 -3
- package/src/components/floating/menu.tsx +0 -189
- package/src/components/floating/menu_common.tsx +0 -31
- package/src/components/floating/menu_components.tsx +0 -99
- package/src/components/image.tsx +0 -24
- package/src/components/index.ts +0 -22
- package/src/components/link.tsx +0 -114
- package/src/components/message.tsx +0 -153
- package/src/components/rating.tsx +0 -106
- package/src/components/readme_renderer/index.ts +0 -3
- package/src/components/readme_renderer/pythonize_value.ts +0 -76
- package/src/components/readme_renderer/table_of_contents.tsx +0 -272
- package/src/components/readme_renderer/utils.tsx +0 -46
- package/src/components/simple_markdown/index.ts +0 -2
- package/src/components/simple_markdown/simple_markdown.tsx +0 -214
- package/src/components/simple_markdown/simple_markdown_components.tsx +0 -293
- package/src/components/tabs/index.ts +0 -2
- package/src/components/tabs/tab.tsx +0 -217
- package/src/components/tabs/tabs.tsx +0 -169
- package/src/components/tag.tsx +0 -196
- package/src/components/text/heading_content.tsx +0 -56
- package/src/components/text/heading_marketing.tsx +0 -55
- package/src/components/text/heading_shared.tsx +0 -55
- package/src/components/text/index.ts +0 -19
- package/src/components/text/text_base.tsx +0 -52
- package/src/components/text/text_content.tsx +0 -104
- package/src/components/text/text_marketing.tsx +0 -152
- package/src/components/text/text_shared.tsx +0 -95
- package/src/components/tile/horizontal_tile.tsx +0 -77
- package/src/components/tile/index.ts +0 -2
- package/src/components/tile/shared.ts +0 -27
- package/src/components/tile/vertical_tile.tsx +0 -59
- package/src/components/to_consolidate/card.tsx +0 -141
- package/src/components/to_consolidate/index.ts +0 -4
- package/src/components/to_consolidate/markdown.tsx +0 -609
- package/src/components/to_consolidate/pagination.tsx +0 -136
- package/src/components/to_consolidate/tab_number_chip.tsx +0 -31
- package/src/design_system/colors/build_color_tokens.js +0 -175
- package/src/design_system/colors/figma_color_tokens.dark.json +0 -886
- package/src/design_system/colors/figma_color_tokens.light.json +0 -886
- package/src/design_system/colors/generated/colors_theme.dark.ts +0 -110
- package/src/design_system/colors/generated/colors_theme.light.ts +0 -110
- package/src/design_system/colors/generated/dark.ts +0 -147
- package/src/design_system/colors/generated/palette.dark.ts +0 -74
- package/src/design_system/colors/generated/properties_theme.ts +0 -179
- package/src/design_system/colors/index.ts +0 -7
- package/src/design_system/colors_theme.ts +0 -213
- package/src/design_system/properties_theme.ts +0 -453
- package/src/design_system/supernova_typography_tokens.json +0 -657
- package/src/design_system/theme.ts +0 -25
- package/src/design_system/tokens/index.ts +0 -5
- package/src/design_system/tokens/layouts.ts +0 -29
- package/src/design_system/tokens/radiuses.ts +0 -22
- package/src/design_system/tokens/shadows.ts +0 -22
- package/src/design_system/tokens/spaces.ts +0 -15
- package/src/design_system/tokens/transitions.ts +0 -19
- package/src/design_system/typography_theme.ts +0 -197
- package/src/index.ts +0 -8
- package/src/type_utils.ts +0 -7
- package/src/ui_dependency_provider.tsx +0 -58
- package/src/utils/copy_to_clipboard.ts +0 -24
- package/src/utils/image_color.ts +0 -42
- package/src/utils/index.ts +0 -4
- package/src/utils/resize_observer.ts +0 -18
- package/src/utils/sanitization.ts +0 -14
- package/tsconfig.build.json +0 -17
- package/tsconfig.json +0 -10
- /package/{src/design_system/colors/generated → style/colors}/dark.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/light.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/palette.dark.scss +0 -0
- /package/{src/design_system/colors/generated → style/colors}/palette.light.scss +0 -0
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
|
-
import React, {
|
|
3
|
-
useCallback,
|
|
4
|
-
useMemo,
|
|
5
|
-
} from 'react';
|
|
6
|
-
import ReactMarkdown from 'react-markdown';
|
|
7
|
-
import type { AllowElement } from 'react-markdown/lib/rehype-filter';
|
|
8
|
-
import remarkToc from 'remark-toc';
|
|
9
|
-
import styled from 'styled-components';
|
|
10
|
-
|
|
11
|
-
import { theme } from '../../design_system/theme.js';
|
|
12
|
-
import { inlineCodeStyles } from '../code/index.js';
|
|
13
|
-
import { Link } from '../link.js';
|
|
14
|
-
import { Text } from '../text/index.js';
|
|
15
|
-
import { cleanMarkdown, slugifyHeadingChildren } from './utils.js';
|
|
16
|
-
|
|
17
|
-
const TOC_HEADING_ID = 'Contents';
|
|
18
|
-
|
|
19
|
-
const StyledTOCLink = styled(Text)`
|
|
20
|
-
display: inline-block;
|
|
21
|
-
color: ${theme.color.neutral.textMuted};
|
|
22
|
-
text-decoration: none;
|
|
23
|
-
|
|
24
|
-
/* Do no change the font style if the heading is defined as bold in the markdown and is wrapped in a <strong> tag */
|
|
25
|
-
strong {
|
|
26
|
-
font-size: inherit !important;
|
|
27
|
-
line-height: inherit !important;
|
|
28
|
-
font-weight: inherit !important;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
&:hover, &.selected {
|
|
32
|
-
color: ${theme.color.primary.text} !important;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
&:before {
|
|
36
|
-
content: " ";
|
|
37
|
-
display: inline-block;
|
|
38
|
-
height: 100%;
|
|
39
|
-
left: 0;
|
|
40
|
-
margin-top: -1px;
|
|
41
|
-
position: absolute;
|
|
42
|
-
width: 1px;
|
|
43
|
-
background-color: ${theme.color.neutral.border};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
&.selected:before {
|
|
47
|
-
background-color: ${theme.color.primary.text};
|
|
48
|
-
}
|
|
49
|
-
`;
|
|
50
|
-
|
|
51
|
-
const StyledTableOfContents = styled.div`
|
|
52
|
-
position: relative;
|
|
53
|
-
overflow: hidden;
|
|
54
|
-
|
|
55
|
-
p {
|
|
56
|
-
margin: 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.level-3 a {
|
|
60
|
-
color: ${theme.color.neutral.textSubtle};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
ul {
|
|
64
|
-
padding-left: ${theme.space.space8} !important;
|
|
65
|
-
list-style: none;
|
|
66
|
-
margin: 0;
|
|
67
|
-
overflow-y: auto;
|
|
68
|
-
|
|
69
|
-
&.level-3 {
|
|
70
|
-
padding-left: ${theme.space.space16} !important;
|
|
71
|
-
max-height: 0;
|
|
72
|
-
overflow: hidden;
|
|
73
|
-
transition: all .3s ease-in-out;
|
|
74
|
-
|
|
75
|
-
&.expanded {
|
|
76
|
-
max-height: 1000px;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.inline-code {
|
|
82
|
-
${inlineCodeStyles}
|
|
83
|
-
}
|
|
84
|
-
`;
|
|
85
|
-
|
|
86
|
-
interface CustomHTMLAnchorElement extends Omit<HTMLAnchorElement, 'children' | 'parentNode'> {
|
|
87
|
-
hash: string;
|
|
88
|
-
tagName: string;
|
|
89
|
-
type: string;
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
|
-
parentNode: any;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const handleScroll = (anchors: CustomHTMLAnchorElement[], headlines: HTMLElement[], anchorLists: HTMLUListElement[] | null, headingOffsetPx: number) => {
|
|
95
|
-
if (!anchors || !headlines) return;
|
|
96
|
-
|
|
97
|
-
// Items that are past scroll
|
|
98
|
-
const headlinesPastScrollPosition = headlines.filter((headline) => {
|
|
99
|
-
return headline.getBoundingClientRect().top - headingOffsetPx < 0;
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Last item that is past the scroll is current in view. If no headline is past the scroll, let's select the first one
|
|
103
|
-
const currentHeadlineId = headlinesPastScrollPosition[headlinesPastScrollPosition.length - 1]?.id || headlines[0]?.id;
|
|
104
|
-
|
|
105
|
-
// Highlighting anchor of current headline
|
|
106
|
-
if (currentHeadlineId) {
|
|
107
|
-
const currentHash = `#${currentHeadlineId}`;
|
|
108
|
-
|
|
109
|
-
anchorLists?.forEach((anchorList) => anchorList.classList.remove('expanded'));
|
|
110
|
-
|
|
111
|
-
// Remove selected class from all anchors and only add it to the current one
|
|
112
|
-
anchors.forEach((anchor) => {
|
|
113
|
-
anchor.classList.remove('selected');
|
|
114
|
-
if (anchor.hash === currentHash) {
|
|
115
|
-
anchor.classList.add('selected');
|
|
116
|
-
|
|
117
|
-
const grandparent = anchor.parentNode?.parentNode;
|
|
118
|
-
|
|
119
|
-
// Structure of the table of content is normalized so we can figure out if section should be expanded
|
|
120
|
-
// by tag and className of neighboring nodes. There are two cases:
|
|
121
|
-
|
|
122
|
-
// 1) If h2 is selected, we want to expand its section with h3 headings
|
|
123
|
-
if (grandparent?.tagName === 'LI' && grandparent.children[1]?.tagName === 'UL' && grandparent.children[1]?.classList.contains('level-3')) {
|
|
124
|
-
grandparent.children[1].classList.add('expanded');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 2) We also want to expand section of h3 headings that follow h1 right away
|
|
128
|
-
if (grandparent?.tagName === 'UL' && grandparent.classList.contains('level-3')) {
|
|
129
|
-
grandparent.classList.add('expanded');
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const assignHeadingLevelsRecursively = (
|
|
137
|
-
{
|
|
138
|
-
children,
|
|
139
|
-
tagName,
|
|
140
|
-
properties,
|
|
141
|
-
}: {
|
|
142
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
143
|
-
children: any[],
|
|
144
|
-
tagName: string,
|
|
145
|
-
properties: { className: string }
|
|
146
|
-
},
|
|
147
|
-
level: number,
|
|
148
|
-
) => {
|
|
149
|
-
if (level > 3) return;
|
|
150
|
-
let currentLevel = level;
|
|
151
|
-
if (tagName === 'ul') {
|
|
152
|
-
// eslint-disable-next-line no-param-reassign
|
|
153
|
-
properties.className = `level-${currentLevel}`; // assign level className
|
|
154
|
-
currentLevel += 1; // increase current heading level;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
children?.forEach((child) => {
|
|
158
|
-
// We only care about ul and li elements - we don't need to traverse any other
|
|
159
|
-
if (child.type === 'element' && (tagName === 'ul' || tagName === 'li')) {
|
|
160
|
-
assignHeadingLevelsRecursively(child, currentLevel);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export interface TableOfContentsProps {
|
|
166
|
-
markdown: string;
|
|
167
|
-
headingOffsetPx?: number; // How far from the top should the toc detect the current heading
|
|
168
|
-
// Function where we can define which elements are allowed in the markdown. See https://github.com/remarkjs/react-markdown#props for more info
|
|
169
|
-
allowElement?: AllowElement;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const TableOfContentsComponent = ({
|
|
173
|
-
markdown,
|
|
174
|
-
headingOffsetPx = 10,
|
|
175
|
-
allowElement,
|
|
176
|
-
...rest
|
|
177
|
-
}: TableOfContentsProps) => {
|
|
178
|
-
const cleanedMarkdown = useMemo(() => {
|
|
179
|
-
const cleanedMarkdownString = cleanMarkdown(markdown);
|
|
180
|
-
return `### ${TOC_HEADING_ID}\n${cleanedMarkdownString}`;
|
|
181
|
-
}, [markdown]);
|
|
182
|
-
|
|
183
|
-
const hasTopLevelHeading = useMemo(() => !!cleanedMarkdown.match(/^#\s.+$/m), [cleanedMarkdown]);
|
|
184
|
-
|
|
185
|
-
const tocRef = useCallback((node: HTMLElement | null) => {
|
|
186
|
-
const anchors = node ? Array.from(node.querySelectorAll('a')) : [];
|
|
187
|
-
const anchorLists = node ? Array.from(node.querySelectorAll('ul')) : null;
|
|
188
|
-
const headlines = (anchors)
|
|
189
|
-
.map((anchor) => document.getElementById(anchor.hash.substr(1)))
|
|
190
|
-
.filter((headline) => headline !== undefined && headline !== null) as HTMLElement[];
|
|
191
|
-
|
|
192
|
-
const scrollHandler = () => handleScroll(anchors, headlines, anchorLists, headingOffsetPx);
|
|
193
|
-
|
|
194
|
-
// Callback refs cannot return cleanup functions - but they are called again with null on unmount
|
|
195
|
-
if (node) {
|
|
196
|
-
window.addEventListener('scroll', scrollHandler);
|
|
197
|
-
} else {
|
|
198
|
-
window.removeEventListener('scroll', scrollHandler);
|
|
199
|
-
}
|
|
200
|
-
scrollHandler(); // call for the first time so we select the first heading without scrolling
|
|
201
|
-
}, [headingOffsetPx]);
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<StyledTableOfContents ref={tocRef} {...rest}>
|
|
205
|
-
<ReactMarkdown
|
|
206
|
-
allowElement={allowElement}
|
|
207
|
-
remarkPlugins={[
|
|
208
|
-
[remarkToc, { heading: TOC_HEADING_ID, maxDepth: 3 }],
|
|
209
|
-
() => ({ children, ...nodeRest }) => {
|
|
210
|
-
// TOC plug-ins only inject content table to existing markdown documents - only generating it is not a common use-case
|
|
211
|
-
// To make is happen, we can just take the generated node where toc is located and throw away the rest.
|
|
212
|
-
// children[0] is the heading where toc is placed (that's plug-in's requirement)
|
|
213
|
-
// children[1] is the generated table of contents we can simply pick
|
|
214
|
-
|
|
215
|
-
let tocContentNode = children[1];
|
|
216
|
-
|
|
217
|
-
// If there is no H1 heading in the readme then assignHeadingLevelsRecursively does not work correctly.
|
|
218
|
-
// We need to 'normalize' the final node to have all the levels we expect
|
|
219
|
-
// - solution is to wrap the content in extra node that mimic this H1 group that remarkToc would normally create
|
|
220
|
-
if (!hasTopLevelHeading) {
|
|
221
|
-
tocContentNode = {
|
|
222
|
-
type: 'list',
|
|
223
|
-
ordered: false,
|
|
224
|
-
spread: false,
|
|
225
|
-
children: [
|
|
226
|
-
{
|
|
227
|
-
type: 'listItem',
|
|
228
|
-
spread: true,
|
|
229
|
-
children: [
|
|
230
|
-
tocContentNode,
|
|
231
|
-
],
|
|
232
|
-
},
|
|
233
|
-
],
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return {
|
|
238
|
-
...nodeRest,
|
|
239
|
-
children: [
|
|
240
|
-
tocContentNode,
|
|
241
|
-
],
|
|
242
|
-
};
|
|
243
|
-
},
|
|
244
|
-
]}
|
|
245
|
-
rehypePlugins={[() => (input) => {
|
|
246
|
-
// this plug-in already works with html node representation so we can assign classNames that we need
|
|
247
|
-
// in order to allow hiding blocks with h3 headings that are out of the viewport
|
|
248
|
-
assignHeadingLevelsRecursively(input.children[0], 1);
|
|
249
|
-
return input;
|
|
250
|
-
}]}
|
|
251
|
-
components={{
|
|
252
|
-
a: ({ children }) => (
|
|
253
|
-
<StyledTOCLink
|
|
254
|
-
forwardedAs={Link}
|
|
255
|
-
to={`#${slugifyHeadingChildren(children)}`}
|
|
256
|
-
py={'space4'}
|
|
257
|
-
>
|
|
258
|
-
{children}
|
|
259
|
-
</StyledTOCLink>
|
|
260
|
-
),
|
|
261
|
-
code: ({ children }) => (
|
|
262
|
-
<code className="inline-code">{children}</code>
|
|
263
|
-
),
|
|
264
|
-
}}
|
|
265
|
-
>
|
|
266
|
-
{cleanedMarkdown}
|
|
267
|
-
</ReactMarkdown>
|
|
268
|
-
</StyledTableOfContents>
|
|
269
|
-
);
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
export const TableOfContents = React.memo(TableOfContentsComponent, (prevProps, nextProps) => _.isEqual(prevProps, nextProps));
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import React, { useCallback } from 'react';
|
|
2
|
-
import type { AllowElement } from 'react-markdown/lib/rehype-filter';
|
|
3
|
-
import slugify from 'slugify';
|
|
4
|
-
|
|
5
|
-
export const slugifyHeadingChildren = (
|
|
6
|
-
headingChildren: React.ReactNode,
|
|
7
|
-
): string | undefined => {
|
|
8
|
-
if (!headingChildren) return undefined;
|
|
9
|
-
|
|
10
|
-
const slugs: string[] = [];
|
|
11
|
-
React.Children.forEach(headingChildren, (child) => {
|
|
12
|
-
if (typeof child === 'string') {
|
|
13
|
-
slugs.push(slugify(child, { lower: true, strict: true }));
|
|
14
|
-
} else if (React.isValidElement(child) && child.props.children) {
|
|
15
|
-
const nestedSlugs = slugifyHeadingChildren(child.props.children);
|
|
16
|
-
if (nestedSlugs) slugs.push(nestedSlugs);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
return slugs.join('-');
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const cleanMarkdown = (markdown: string, removeFirstH1?: boolean): string => {
|
|
24
|
-
// Remove the table of contents as we are generating our own
|
|
25
|
-
let clean = markdown
|
|
26
|
-
.replace(/<!-- toc start -->.*?<!-- toc end -->/s, '')
|
|
27
|
-
.replace(/##.*content.*?\n*<!-- toc -->(.|[\r\n])*<!-- tocstop -->\n*/, '');
|
|
28
|
-
|
|
29
|
-
// Remove first h1 if removeFirstH1 is true
|
|
30
|
-
if (removeFirstH1) clean = clean.replace(removeFirstH1 ? /^#\s.+$/m : '', '');
|
|
31
|
-
|
|
32
|
-
return clean.trim();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// This removes the first element if it's a `h1` containing exactly the Actor title
|
|
36
|
-
export const useActorTitleHeadingFilter = (actorTitle: string): AllowElement => {
|
|
37
|
-
return useCallback((element, index, parent) => {
|
|
38
|
-
if (parent.type === 'root'
|
|
39
|
-
&& index === 0
|
|
40
|
-
&& element.tagName === 'h1'
|
|
41
|
-
&& element.children.length === 1
|
|
42
|
-
&& element.children[0].type === 'text'
|
|
43
|
-
&& element.children[0].value?.toLowerCase() === actorTitle.toLowerCase()) return false;
|
|
44
|
-
return true;
|
|
45
|
-
}, [actorTitle]);
|
|
46
|
-
};
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import type { Element, Root, Text as TextNode } from 'hast';
|
|
2
|
-
import React, { useCallback, useMemo, useRef } from 'react';
|
|
3
|
-
import type { Components } from 'react-markdown';
|
|
4
|
-
import ReactMarkdown, { uriTransformer } from 'react-markdown';
|
|
5
|
-
import type { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown';
|
|
6
|
-
import rehypeRaw from 'rehype-raw';
|
|
7
|
-
import rehypeSanitize from 'rehype-sanitize';
|
|
8
|
-
import remarkGfm from 'remark-gfm';
|
|
9
|
-
import styled from 'styled-components';
|
|
10
|
-
import type { Pluggable, PluggableList } from 'unified';
|
|
11
|
-
import { visit } from 'unist-util-visit';
|
|
12
|
-
|
|
13
|
-
import { theme } from '../../design_system/theme.js';
|
|
14
|
-
import { useSharedUiDependencies } from '../../ui_dependency_provider.js';
|
|
15
|
-
import { Box } from '../box.js';
|
|
16
|
-
import { isUrlExternal } from '../link.js';
|
|
17
|
-
import { cleanMarkdown } from '../readme_renderer/utils.js';
|
|
18
|
-
import { HeadingContent } from '../text/heading_content.js';
|
|
19
|
-
import { Heading, Text } from '../text/index.js';
|
|
20
|
-
import { TextContent } from '../text/text_content.js';
|
|
21
|
-
import {
|
|
22
|
-
MarkdownBlockQuote,
|
|
23
|
-
MarkdownCode,
|
|
24
|
-
MarkdownLink,
|
|
25
|
-
MarkdownTable,
|
|
26
|
-
} from './simple_markdown_components.js';
|
|
27
|
-
|
|
28
|
-
export type SimpleMarkdownComponents = Components;
|
|
29
|
-
|
|
30
|
-
export const defaultAllowedElements = [
|
|
31
|
-
'a',
|
|
32
|
-
'b',
|
|
33
|
-
'blockquote',
|
|
34
|
-
'br',
|
|
35
|
-
'center',
|
|
36
|
-
'code',
|
|
37
|
-
'del',
|
|
38
|
-
'em',
|
|
39
|
-
'h1',
|
|
40
|
-
'h2',
|
|
41
|
-
'h3',
|
|
42
|
-
'h4',
|
|
43
|
-
'h5',
|
|
44
|
-
'hr',
|
|
45
|
-
'i',
|
|
46
|
-
'img',
|
|
47
|
-
'li',
|
|
48
|
-
'ol',
|
|
49
|
-
'p',
|
|
50
|
-
'pre',
|
|
51
|
-
'span',
|
|
52
|
-
'strong',
|
|
53
|
-
'table',
|
|
54
|
-
'tbody',
|
|
55
|
-
'td',
|
|
56
|
-
'tfoot',
|
|
57
|
-
'th',
|
|
58
|
-
'thead',
|
|
59
|
-
'tr',
|
|
60
|
-
'u',
|
|
61
|
-
'ul',
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
const StyledMarkdown = styled(ReactMarkdown)`
|
|
65
|
-
scroll-margin-top: 10px;
|
|
66
|
-
|
|
67
|
-
@font-face {
|
|
68
|
-
font-family: "ellipsis-font";
|
|
69
|
-
src: local("Courier");
|
|
70
|
-
unicode-range: U+2026;
|
|
71
|
-
size-adjust: 0%;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
img {
|
|
75
|
-
max-width: 100%;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
hr {
|
|
79
|
-
color: ${theme.color.neutral.border};
|
|
80
|
-
}
|
|
81
|
-
`;
|
|
82
|
-
|
|
83
|
-
// Function to recursively process unsupported elements
|
|
84
|
-
const unwrapUnsupportedElement = (node: Element): (Element | TextNode)[] => {
|
|
85
|
-
return node.children.flatMap((child) => {
|
|
86
|
-
if (child.type === 'text') {
|
|
87
|
-
return child; // Keep text as is
|
|
88
|
-
}
|
|
89
|
-
if (child.type === 'element') {
|
|
90
|
-
if (defaultAllowedElements.includes(child.tagName)) {
|
|
91
|
-
return child; // Keep supported elements
|
|
92
|
-
}
|
|
93
|
-
return unwrapUnsupportedElement(child as Element);
|
|
94
|
-
}
|
|
95
|
-
return []; // Ignore other node types
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const getUnsupportedRehypeTagsSanitationPlugIn = (
|
|
100
|
-
allowedElements: string[],
|
|
101
|
-
): Pluggable<unknown[]> => () => (tree: Root) => {
|
|
102
|
-
visit(tree, 'element', (node, index, parent) => {
|
|
103
|
-
if (!allowedElements.includes(node.tagName) && parent && typeof index === 'number') {
|
|
104
|
-
// Replace unsupported element with its valid children
|
|
105
|
-
parent.children.splice(index, 1, ...unwrapUnsupportedElement(node));
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export const defaultRehypePlugins = [rehypeRaw];
|
|
111
|
-
export const defaultRemarkPlugins = [remarkGfm];
|
|
112
|
-
|
|
113
|
-
// TODO: Add Image component
|
|
114
|
-
const regularMarkdownSizeComponents: Components = {
|
|
115
|
-
h1: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading1'>{children}</HeadingContent>,
|
|
116
|
-
h2: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading2'>{children}</HeadingContent>,
|
|
117
|
-
h3: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading3'>{children}</HeadingContent>,
|
|
118
|
-
h4: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading4'>{children}</HeadingContent>,
|
|
119
|
-
h5: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading5'>{children}</HeadingContent>,
|
|
120
|
-
h6: ({ children }) => <HeadingContent mt='space32' mb='space16' type='heading6'>{children}</HeadingContent>,
|
|
121
|
-
p: ({ children }) => (<TextContent my='space16'>{children}</TextContent>),
|
|
122
|
-
strong: ({ children }) => <TextContent as='strong' weight='bold'>{children}</TextContent>,
|
|
123
|
-
b: ({ children }) => <TextContent as='b' weight='bold'>{children}</TextContent>,
|
|
124
|
-
th: ({ children }) => <TextContent as='th' weight='bold'>{children}</TextContent>,
|
|
125
|
-
blockquote: ({ children }) => <MarkdownBlockQuote>{children}</MarkdownBlockQuote>,
|
|
126
|
-
table: ({ children }) => <MarkdownTable>{children}</MarkdownTable>,
|
|
127
|
-
ul: ({ children }) => <Box as='ul' pl='space32'>{children}</Box>,
|
|
128
|
-
ol: ({ children, start }) => <TextContent as='ol' pl='space32' start={start}>{children}</TextContent>,
|
|
129
|
-
li: ({ children }) => <TextContent as='li' mt='space4'>{children}</TextContent>,
|
|
130
|
-
a: ({ children, href }) => <MarkdownLink to={href}>{children}</MarkdownLink>,
|
|
131
|
-
code: ({ children, inline }) => <MarkdownCode inline={inline} size='regular'>{children}</MarkdownCode>,
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const smallMarkdownSizeComponents: Components = {
|
|
135
|
-
h1: ({ children }) => <Heading mt='space32' mb='space16' type='title2xl'>{children}</Heading>,
|
|
136
|
-
h2: ({ children }) => <Heading mt='space32' mb='space16' type='titleXl'>{children}</Heading>,
|
|
137
|
-
h3: ({ children }) => <Heading mt='space32' mb='space16' type='titleL'>{children}</Heading>,
|
|
138
|
-
h4: ({ children }) => <Heading mt='space32' mb='space16' type='titleM'>{children}</Heading>,
|
|
139
|
-
h5: ({ children }) => <Heading mt='space32' mb='space16' type='titleS'>{children}</Heading>,
|
|
140
|
-
h6: ({ children }) => <Heading mt='space32' mb='space16' type='titleXs'>{children}</Heading>,
|
|
141
|
-
p: ({ children }) => (<Text my='space16'>{children}</Text>),
|
|
142
|
-
strong: ({ children }) => <Text as='strong' weight='bold'>{children}</Text>,
|
|
143
|
-
b: ({ children }) => <Text as='b' weight='bold'>{children}</Text>,
|
|
144
|
-
th: ({ children }) => <Text as='th' weight='bold'>{children}</Text>,
|
|
145
|
-
blockquote: ({ children }) => <MarkdownBlockQuote>{children}</MarkdownBlockQuote>,
|
|
146
|
-
table: ({ children }) => <MarkdownTable>{children}</MarkdownTable>,
|
|
147
|
-
ul: ({ children }) => <Box as='ul' pl='space32'>{children}</Box>,
|
|
148
|
-
ol: ({ children, start }) => <Text as='ol' pl='space32' start={start}>{children}</Text>,
|
|
149
|
-
li: ({ children }) => <Text as='li' mt='space4'>{children}</Text>,
|
|
150
|
-
a: ({ children, href }) => <MarkdownLink to={href}>{children}</MarkdownLink>,
|
|
151
|
-
code: ({ children, inline }) => <MarkdownCode inline={inline} size='small'>{children}</MarkdownCode>,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
type MarkdownSize = 'regular' | 'small';
|
|
155
|
-
|
|
156
|
-
interface SimpleMarkdownProps extends ReactMarkdownOptions {
|
|
157
|
-
size?: MarkdownSize,
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const useDefaultUrlTransform = () => {
|
|
161
|
-
const { windowLocationHost } = useSharedUiDependencies();
|
|
162
|
-
|
|
163
|
-
return useCallback((url: string) => {
|
|
164
|
-
if (!isUrlExternal(url, windowLocationHost)) {
|
|
165
|
-
// We want to make sure internal links will be relative links without https://host at the beginning because Link doesn't work with these
|
|
166
|
-
return url.replace(/^(https?:\/\/)?(www\.)?[^/]+/, '') || '/';
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return url;
|
|
170
|
-
}, [windowLocationHost]);
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
export const SimpleMarkdown: React.FC<SimpleMarkdownProps> = ({
|
|
174
|
-
size = 'regular', // small is default for console
|
|
175
|
-
children: markdown,
|
|
176
|
-
components,
|
|
177
|
-
rehypePlugins,
|
|
178
|
-
remarkPlugins,
|
|
179
|
-
transformLinkUri,
|
|
180
|
-
allowedElements,
|
|
181
|
-
...rest
|
|
182
|
-
}) => {
|
|
183
|
-
const cleanedMarkdown = useMemo(() => cleanMarkdown(markdown), [markdown]);
|
|
184
|
-
|
|
185
|
-
const effectiveAllowedElements = useRef(allowedElements || defaultAllowedElements);
|
|
186
|
-
|
|
187
|
-
const effectiveComponents = useRef({
|
|
188
|
-
...(size === 'regular' ? regularMarkdownSizeComponents : smallMarkdownSizeComponents),
|
|
189
|
-
...components,
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const rehypePluginsRef = useRef<PluggableList>([
|
|
193
|
-
...(rehypePlugins || [...defaultRehypePlugins, getUnsupportedRehypeTagsSanitationPlugIn(effectiveAllowedElements.current)]),
|
|
194
|
-
rehypeSanitize, // lets always sanitize the output
|
|
195
|
-
]);
|
|
196
|
-
|
|
197
|
-
const defaultUrlTransform = useDefaultUrlTransform();
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<StyledMarkdown
|
|
201
|
-
components={effectiveComponents.current}
|
|
202
|
-
rehypePlugins={rehypePluginsRef.current}
|
|
203
|
-
remarkPlugins={remarkPlugins || defaultRemarkPlugins}
|
|
204
|
-
allowedElements={effectiveAllowedElements.current}
|
|
205
|
-
transformLinkUri={(href, children, title) => {
|
|
206
|
-
const transformed = transformLinkUri ? transformLinkUri(href, children, title) : defaultUrlTransform(href);
|
|
207
|
-
return uriTransformer(transformed);
|
|
208
|
-
}}
|
|
209
|
-
{...rest}
|
|
210
|
-
>
|
|
211
|
-
{cleanedMarkdown}
|
|
212
|
-
</StyledMarkdown>
|
|
213
|
-
);
|
|
214
|
-
};
|