@apify/ui-library 1.119.0 → 1.120.0

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.
Files changed (25) hide show
  1. package/dist/src/components/simple_markdown/simple_markdown_components.d.ts.map +1 -1
  2. package/dist/src/components/simple_markdown/simple_markdown_components.js +23 -6
  3. package/dist/src/components/simple_markdown/simple_markdown_components.js.map +1 -1
  4. package/dist/tsconfig.build.tsbuildinfo +1 -1
  5. package/package.json +2 -2
  6. package/src/components/card_container.stories.tsx +2 -1
  7. package/src/components/code/code_block/code_block.stories.jsx +1 -1
  8. package/src/components/code/inline_code/inline_code.stories.tsx +1 -1
  9. package/src/components/code/one_line_code/one_line_code.stories.tsx +1 -1
  10. package/src/components/readme_renderer/table_of_contents.stories.tsx +476 -0
  11. package/src/components/simple_markdown/simple_markdown.stories.tsx +1 -1
  12. package/src/components/simple_markdown/simple_markdown_components.tsx +27 -5
  13. package/src/components/text/heading_content.stories.tsx +167 -0
  14. package/src/components/text/heading_marketing.stories.tsx +123 -0
  15. package/src/components/text/heading_shared.stories.tsx +118 -0
  16. package/src/components/text/text_content.stories.tsx +189 -0
  17. package/src/components/text/text_marketing.stories.tsx +187 -0
  18. package/src/components/text/text_shared.stories.tsx +246 -0
  19. package/src/components/tile/horizontal_tile.stories.tsx +105 -0
  20. package/src/components/tile/vertical_tile.stories.tsx +167 -0
  21. package/src/components/to_consolidate/card.stories.tsx +91 -0
  22. package/src/components/to_consolidate/markdown.stories.tsx +160 -0
  23. package/src/components/to_consolidate/pagination.stories.tsx +64 -0
  24. package/src/components/to_consolidate/tab_number_chip.stories.tsx +113 -0
  25. package/src/components/text/text.stories.tsx +0 -61
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apify/ui-library",
3
- "version": "1.119.0",
3
+ "version": "1.120.0",
4
4
  "description": "React UI library used by apify.com",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -64,5 +64,5 @@
64
64
  "src",
65
65
  "style"
66
66
  ],
67
- "gitHead": "5c6e9bc263b489ab938a090589b1a291fcb7f381"
67
+ "gitHead": "ad7a5921f83c7575ecea7fca3b3843cdc7f04a8f"
68
68
  }
@@ -7,7 +7,7 @@ import { CardContainer, type CardContainerProps } from './card_container.js';
7
7
  import { IconButton } from './icon_button.js';
8
8
 
9
9
  export default {
10
- title: 'UI-Library/CardContainer',
10
+ title: 'UI-Library/Cards/CardContainer',
11
11
  component: CardContainer,
12
12
  argTypes: {
13
13
  headerPlacement: {
@@ -15,6 +15,7 @@ export default {
15
15
  options: ['TOP', 'BOTTOM'],
16
16
  },
17
17
  },
18
+ tags: ['new'],
18
19
  } as Meta<CardContainerProps>;
19
20
 
20
21
  type Story = StoryObj<CardContainerProps>;
@@ -1,7 +1,7 @@
1
1
  import { CodeBlock } from './code_block.tsx';
2
2
 
3
3
  export default {
4
- title: 'ui-library/CodeBlock',
4
+ title: 'ui-library/Code/CodeBlock',
5
5
  parameters: {
6
6
  layout: 'centered',
7
7
  design: {
@@ -9,7 +9,7 @@ import { InlineCode } from './inline_code.js';
9
9
  * including different sizes and copy button functionality.
10
10
  */
11
11
  export default {
12
- title: 'ui-library/InlineCode',
12
+ title: 'ui-library/Code/InlineCode',
13
13
  component: InlineCode,
14
14
  tags: [],
15
15
  argTypes: {
@@ -8,7 +8,7 @@ import { OneLineCode, type OneLineCodeProps } from './one_line_code.js';
8
8
  * including different languages, HTTP methods, and interactive features.
9
9
  */
10
10
  export default {
11
- title: 'ui-library/OneLineCode',
11
+ title: 'ui-library/Code/OneLineCode',
12
12
  component: OneLineCode,
13
13
  tags: [],
14
14
  argTypes: {
@@ -0,0 +1,476 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import styled from 'styled-components';
3
+
4
+ import { TableOfContents, type TableOfContentsProps } from './table_of_contents.js';
5
+
6
+ export default {
7
+ title: 'UI-Library/TableOfContents',
8
+ component: TableOfContents,
9
+ argTypes: {
10
+ markdown: {
11
+ control: 'text',
12
+ description: 'The markdown content to generate table of contents from',
13
+ },
14
+ headingOffsetPx: {
15
+ control: { type: 'number', min: 0 },
16
+ description: 'Offset from the top for detecting current heading position',
17
+ },
18
+ allowElement: {
19
+ control: false,
20
+ description: 'Function to filter allowed markdown elements',
21
+ },
22
+ },
23
+ } as Meta<TableOfContentsProps>;
24
+
25
+ type Story = StoryObj<TableOfContentsProps>;
26
+
27
+ const StoryWrapper = styled.div`
28
+ display: grid;
29
+ grid-template-columns: 250px 1fr;
30
+ gap: 2rem;
31
+ max-width: 1200px;
32
+ `;
33
+
34
+ const ContentArea = styled.div`
35
+ padding: 2rem;
36
+
37
+ h1, h2, h3 {
38
+ margin-top: 3rem;
39
+ margin-bottom: 1rem;
40
+ }
41
+
42
+ p {
43
+ margin-bottom: 1rem;
44
+ line-height: 1.6;
45
+ }
46
+ `;
47
+
48
+ const TOCContainer = styled.div`
49
+ position: sticky;
50
+ top: 2rem;
51
+ max-height: calc(100vh - 4rem);
52
+ overflow-y: auto;
53
+ `;
54
+
55
+ const basicMarkdown = `# Getting Started
56
+
57
+ This is the introduction section with some content.
58
+
59
+ ## Installation
60
+
61
+ Instructions for installing the package.
62
+
63
+ ## Configuration
64
+
65
+ How to configure your project.
66
+
67
+ ### Basic Setup
68
+
69
+ Initial configuration steps.
70
+
71
+ ### Advanced Options
72
+
73
+ More complex configuration scenarios.
74
+
75
+ ## Usage
76
+
77
+ Examples of how to use the component.
78
+
79
+ ### Basic Example
80
+
81
+ A simple usage example.
82
+
83
+ ### Advanced Example
84
+
85
+ A more complex usage scenario.
86
+
87
+ ## API Reference
88
+
89
+ Details about the API.
90
+ `;
91
+
92
+ const markdownWithoutH1 = `## Overview
93
+
94
+ This document starts with H2 headings.
95
+
96
+ ## Features
97
+
98
+ List of available features.
99
+
100
+ ### Feature One
101
+
102
+ Description of the first feature.
103
+
104
+ ### Feature Two
105
+
106
+ Description of the second feature.
107
+
108
+ ## Installation
109
+
110
+ How to install.
111
+
112
+ ### Prerequisites
113
+
114
+ What you need before installing.
115
+
116
+ ### Steps
117
+
118
+ Installation steps.
119
+ `;
120
+
121
+ const longMarkdown = `# Comprehensive Guide
122
+
123
+ An extensive guide with many sections.
124
+
125
+ ## Section 1: Introduction
126
+
127
+ Introduction content here.
128
+
129
+ ### Subsection 1.1
130
+
131
+ Details about subsection 1.1.
132
+
133
+ ### Subsection 1.2
134
+
135
+ Details about subsection 1.2.
136
+
137
+ ### Subsection 1.3
138
+
139
+ Details about subsection 1.3.
140
+
141
+ ## Section 2: Getting Started
142
+
143
+ Getting started content.
144
+
145
+ ### Subsection 2.1
146
+
147
+ More details here.
148
+
149
+ ### Subsection 2.2
150
+
151
+ Additional information.
152
+
153
+ ### Subsection 2.3
154
+
155
+ Even more content.
156
+
157
+ ## Section 3: Core Concepts
158
+
159
+ Core concepts explained.
160
+
161
+ ### Subsection 3.1
162
+
163
+ First concept.
164
+
165
+ ### Subsection 3.2
166
+
167
+ Second concept.
168
+
169
+ ### Subsection 3.3
170
+
171
+ Third concept.
172
+
173
+ ## Section 4: Advanced Topics
174
+
175
+ Advanced material.
176
+
177
+ ### Subsection 4.1
178
+
179
+ Advanced topic 1.
180
+
181
+ ### Subsection 4.2
182
+
183
+ Advanced topic 2.
184
+
185
+ ## Section 5: Examples
186
+
187
+ Code examples and use cases.
188
+
189
+ ### Subsection 5.1
190
+
191
+ Example 1.
192
+
193
+ ### Subsection 5.2
194
+
195
+ Example 2.
196
+
197
+ ## Section 6: Troubleshooting
198
+
199
+ Common issues and solutions.
200
+
201
+ ### Subsection 6.1
202
+
203
+ Issue 1.
204
+
205
+ ### Subsection 6.2
206
+
207
+ Issue 2.
208
+
209
+ ## Section 7: FAQ
210
+
211
+ Frequently asked questions.
212
+
213
+ ### Question 1
214
+
215
+ Answer to question 1.
216
+
217
+ ### Question 2
218
+
219
+ Answer to question 2.
220
+
221
+ ## Conclusion
222
+
223
+ Final thoughts and summary.
224
+ `;
225
+
226
+ const markdownWithCode = `# API Documentation
227
+
228
+ Documentation with code examples in headings.
229
+
230
+ ## \`initialize()\` Method
231
+
232
+ Details about the initialize method.
233
+
234
+ ### Parameters
235
+
236
+ List of parameters.
237
+
238
+ ### Return Value
239
+
240
+ What the method returns.
241
+
242
+ ## \`configure(options)\` Method
243
+
244
+ Configuration method details.
245
+
246
+ ### \`options.setting1\`
247
+
248
+ First setting.
249
+
250
+ ### \`options.setting2\`
251
+
252
+ Second setting.
253
+
254
+ ## Usage Examples
255
+
256
+ How to use the API.
257
+ `;
258
+
259
+ const simpleMarkdown = `# Quick Start
260
+
261
+ A simple document.
262
+
263
+ ## Step 1
264
+
265
+ First step.
266
+
267
+ ## Step 2
268
+
269
+ Second step.
270
+
271
+ ## Step 3
272
+
273
+ Third step.
274
+ `;
275
+
276
+ /**
277
+ * Basic table of contents with H1, H2, and H3 headings
278
+ */
279
+ export const Default: Story = {
280
+ args: {
281
+ markdown: basicMarkdown,
282
+ },
283
+ render: (args) => (
284
+ <StoryWrapper>
285
+ <TOCContainer>
286
+ <TableOfContents {...args} />
287
+ </TOCContainer>
288
+ <ContentArea dangerouslySetInnerHTML={{ __html: `
289
+ <h1 id="getting-started">Getting Started</h1>
290
+ <p>This is the introduction section with some content.</p>
291
+
292
+ <h2 id="installation">Installation</h2>
293
+ <p>Instructions for installing the package.</p>
294
+
295
+ <h2 id="configuration">Configuration</h2>
296
+ <p>How to configure your project.</p>
297
+
298
+ <h3 id="basic-setup">Basic Setup</h3>
299
+ <p>Initial configuration steps.</p>
300
+
301
+ <h3 id="advanced-options">Advanced Options</h3>
302
+ <p>More complex configuration scenarios.</p>
303
+
304
+ <h2 id="usage">Usage</h2>
305
+ <p>Examples of how to use the component.</p>
306
+
307
+ <h3 id="basic-example">Basic Example</h3>
308
+ <p>A simple usage example.</p>
309
+
310
+ <h3 id="advanced-example">Advanced Example</h3>
311
+ <p>A more complex usage scenario.</p>
312
+
313
+ <h2 id="api-reference">API Reference</h2>
314
+ <p>Details about the API.</p>
315
+ ` }} />
316
+ </StoryWrapper>
317
+ ),
318
+ };
319
+
320
+ /**
321
+ * Table of contents for markdown without H1 heading
322
+ */
323
+ export const WithoutH1Heading: Story = {
324
+ args: {
325
+ markdown: markdownWithoutH1,
326
+ },
327
+ render: (args) => (
328
+ <StoryWrapper>
329
+ <TOCContainer>
330
+ <TableOfContents {...args} />
331
+ </TOCContainer>
332
+ <ContentArea dangerouslySetInnerHTML={{ __html: `
333
+ <h2 id="overview">Overview</h2>
334
+ <p>This document starts with H2 headings.</p>
335
+
336
+ <h2 id="features">Features</h2>
337
+ <p>List of available features.</p>
338
+
339
+ <h3 id="feature-one">Feature One</h3>
340
+ <p>Description of the first feature.</p>
341
+
342
+ <h3 id="feature-two">Feature Two</h3>
343
+ <p>Description of the second feature.</p>
344
+
345
+ <h2 id="installation">Installation</h2>
346
+ <p>How to install.</p>
347
+
348
+ <h3 id="prerequisites">Prerequisites</h3>
349
+ <p>What you need before installing.</p>
350
+
351
+ <h3 id="steps">Steps</h3>
352
+ <p>Installation steps.</p>
353
+ ` }} />
354
+ </StoryWrapper>
355
+ ),
356
+ };
357
+
358
+ /**
359
+ * Table of contents with many sections (scrollable)
360
+ */
361
+ export const ManySection: Story = {
362
+ args: {
363
+ markdown: longMarkdown,
364
+ },
365
+ render: (args) => (
366
+ <StoryWrapper>
367
+ <TOCContainer>
368
+ <TableOfContents {...args} />
369
+ </TOCContainer>
370
+ <ContentArea>
371
+ <p style={{ marginBottom: '2rem' }}>
372
+ Scroll down to see the table of contents highlighting different sections.
373
+ The TOC stays sticky while scrolling through content.
374
+ </p>
375
+ {Array.from({ length: 7 }, (_, i) => (
376
+ <div key={i}>
377
+ <h2 id={`section-${i + 1}`}>Section {i + 1}</h2>
378
+ <p>Content for section {i + 1}.</p>
379
+ {Array.from({ length: 3 }, (__, j) => (
380
+ <div key={j}>
381
+ <h3 id={`subsection-${i + 1}-${j + 1}`}>Subsection {i + 1}.{j + 1}</h3>
382
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
383
+ Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
384
+ <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
385
+ </div>
386
+ ))}
387
+ </div>
388
+ ))}
389
+ </ContentArea>
390
+ </StoryWrapper>
391
+ ),
392
+ };
393
+
394
+ /**
395
+ * Table of contents with inline code in headings
396
+ */
397
+ export const WithCodeInHeadings: Story = {
398
+ args: {
399
+ markdown: markdownWithCode,
400
+ },
401
+ render: (args) => (
402
+ <StoryWrapper>
403
+ <TOCContainer>
404
+ <TableOfContents {...args} />
405
+ </TOCContainer>
406
+ <ContentArea dangerouslySetInnerHTML={{ __html: `
407
+ <h1 id="api-documentation">API Documentation</h1>
408
+ <p>Documentation with code examples in headings.</p>
409
+
410
+ <h2 id="initialize-method"><code>initialize()</code> Method</h2>
411
+ <p>Details about the initialize method.</p>
412
+
413
+ <h3 id="parameters">Parameters</h3>
414
+ <p>List of parameters.</p>
415
+
416
+ <h3 id="return-value">Return Value</h3>
417
+ <p>What the method returns.</p>
418
+
419
+ <h2 id="configureoptions-method"><code>configure(options)</code> Method</h2>
420
+ <p>Configuration method details.</p>
421
+
422
+ <h3 id="optionssetting1"><code>options.setting1</code></h3>
423
+ <p>First setting.</p>
424
+
425
+ <h3 id="optionssetting2"><code>options.setting2</code></h3>
426
+ <p>Second setting.</p>
427
+
428
+ <h2 id="usage-examples">Usage Examples</h2>
429
+ <p>How to use the API.</p>
430
+ ` }} />
431
+ </StoryWrapper>
432
+ ),
433
+ };
434
+
435
+ /**
436
+ * Simple table of contents with flat structure
437
+ */
438
+ export const SimpleFlat: Story = {
439
+ args: {
440
+ markdown: simpleMarkdown,
441
+ },
442
+ render: (args) => (
443
+ <StoryWrapper>
444
+ <TOCContainer>
445
+ <TableOfContents {...args} />
446
+ </TOCContainer>
447
+ <ContentArea dangerouslySetInnerHTML={{ __html: `
448
+ <h1 id="quick-start">Quick Start</h1>
449
+ <p>A simple document.</p>
450
+
451
+ <h2 id="step-1">Step 1</h2>
452
+ <p>First step.</p>
453
+
454
+ <h2 id="step-2">Step 2</h2>
455
+ <p>Second step.</p>
456
+
457
+ <h2 id="step-3">Step 3</h2>
458
+ <p>Third step.</p>
459
+ ` }} />
460
+ </StoryWrapper>
461
+ ),
462
+ };
463
+
464
+ /**
465
+ * Table of contents only (without content side-by-side)
466
+ */
467
+ export const TOCOnly: Story = {
468
+ args: {
469
+ markdown: basicMarkdown,
470
+ },
471
+ render: (args) => (
472
+ <div style={{ maxWidth: '300px' }}>
473
+ <TableOfContents {...args} />
474
+ </div>
475
+ ),
476
+ };
@@ -62,7 +62,7 @@ const Template = (props: SimpleMarkdownProps) => {
62
62
  };
63
63
 
64
64
  export default {
65
- title: 'UI-Library/Markdown',
65
+ title: 'UI-Library/Markdown/SimpleMarkdown',
66
66
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
67
  component: SimpleMarkdown as any,
68
68
  };
@@ -1,3 +1,4 @@
1
+ import type { ElementContent } from 'hast';
1
2
  import qs from 'query-string';
2
3
  import type React from 'react';
3
4
  import type { ExtraProps as MarkdownComponentExtraProps } from 'react-markdown';
@@ -14,7 +15,7 @@ import type { LinkProps } from '../link.js';
14
15
  import { Link } from '../link.js';
15
16
  import { slugifyHeadingChildren } from '../readme_renderer/utils.js';
16
17
  import type { HeadingSharedProps } from '../text/heading_shared.js';
17
- import { Heading } from '../text/index.js';
18
+ import { Heading, Text } from '../text/index.js';
18
19
  import type { SharedTextProps, SharedTextSize } from '../text/text_shared.js';
19
20
 
20
21
  const simpleMarkdownClassNames = {
@@ -282,17 +283,38 @@ export const MarkdownTable = styled.table`
282
283
  }
283
284
  `;
284
285
 
286
+ /**
287
+ * Helper function to extract video src from markdown node child.
288
+ * Handles both plain text URLs and link elements.
289
+ */
290
+ const getMarkdownVideoSrc = (child?: ElementContent): string | undefined => {
291
+ // Check if it's a plain text YouTube/Vimeo URL
292
+ if (child?.type === 'text') {
293
+ return getVideoSrc(child.value);
294
+ }
295
+
296
+ // Check if it's a link element with YouTube/Vimeo URL
297
+ if (child?.type === 'element' && child?.tagName === 'a') {
298
+ const linkHref = child?.properties?.href;
299
+ if (linkHref && typeof linkHref === 'string') {
300
+ return getVideoSrc(linkHref);
301
+ }
302
+ }
303
+
304
+ return undefined;
305
+ };
306
+
285
307
  // TODO: This should be used for readmes
286
308
  export const MarkdownParagraphContent: React.FC<SharedTextProps & MarkdownComponentExtraProps> = async ({
287
309
  children,
288
310
  node,
311
+ ...textProps
289
312
  }) => {
290
313
  const child = node?.children[0];
291
- const isText = child?.type === 'text';
314
+ const videoSrc = getMarkdownVideoSrc(child);
292
315
 
293
- const videoSrc = isText && getVideoSrc(child.value);
294
316
  if (videoSrc) return <MarkdownVideo src={videoSrc} />;
295
317
 
296
- // the || null part is important because non-supported elements will fall back to this paragraph component;
297
- return children || null;
318
+ // Render the children as a paragraph
319
+ return <Text as='p' my='space16' {...textProps}>{children}</Text>;
298
320
  };