@patternfly/quickstarts 6.3.0-prerelease.1 → 6.3.0-prerelease.10

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 (137) hide show
  1. package/dist/ConsoleInternal/components/markdown-view.d.ts +2 -2
  2. package/dist/ConsoleInternal/components/utils/camel-case-wrap.d.ts +1 -1
  3. package/dist/ConsoleInternal/components/utils/status-box.d.ts +3 -3
  4. package/dist/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.d.ts +3 -3
  5. package/dist/ConsoleShared/src/components/markdown-extensions/accordion-extension.d.ts +1 -1
  6. package/dist/ConsoleShared/src/components/markdown-extensions/accordion-render-extension.d.ts +2 -2
  7. package/dist/ConsoleShared/src/components/markdown-extensions/admonition-extension.d.ts +1 -1
  8. package/dist/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.d.ts +2 -2
  9. package/dist/ConsoleShared/src/components/modal/Modal.d.ts +3 -3
  10. package/dist/ConsoleShared/src/components/popper/Portal.d.ts +3 -3
  11. package/dist/ConsoleShared/src/components/popper/SimplePopper.d.ts +3 -3
  12. package/dist/ConsoleShared/src/components/spotlight/InteractiveSpotlight.d.ts +3 -2
  13. package/dist/ConsoleShared/src/components/spotlight/Spotlight.d.ts +2 -2
  14. package/dist/ConsoleShared/src/components/spotlight/StaticSpotlight.d.ts +3 -2
  15. package/dist/ConsoleShared/src/components/status/GenericStatus.d.ts +4 -4
  16. package/dist/ConsoleShared/src/components/status/NotStartedIcon.d.ts +1 -2
  17. package/dist/ConsoleShared/src/components/status/PopoverStatus.d.ts +4 -4
  18. package/dist/ConsoleShared/src/components/status/Status.d.ts +3 -3
  19. package/dist/ConsoleShared/src/components/status/StatusIconAndText.d.ts +3 -3
  20. package/dist/ConsoleShared/src/components/status/icons.d.ts +4 -4
  21. package/dist/ConsoleShared/src/components/status/statuses.d.ts +4 -4
  22. package/dist/ConsoleShared/src/components/utils/FallbackImg.d.ts +3 -3
  23. package/dist/ConsoleShared/src/utils/useCombineRefs.d.ts +2 -2
  24. package/dist/HelpTopicDrawer.d.ts +3 -3
  25. package/dist/HelpTopicPanelContent.d.ts +2 -2
  26. package/dist/QuickStartCatalogPage.d.ts +3 -3
  27. package/dist/QuickStartCloseModal.d.ts +2 -2
  28. package/dist/QuickStartContainer.d.ts +2 -2
  29. package/dist/QuickStartController.d.ts +2 -2
  30. package/dist/QuickStartDrawer.d.ts +2 -2
  31. package/dist/QuickStartDrawerContent.d.ts +2 -2
  32. package/dist/QuickStartMarkdownView.d.ts +2 -2
  33. package/dist/QuickStartPanelContent.d.ts +2 -2
  34. package/dist/catalog/Catalog/QuickStartCatalogHeader.d.ts +2 -2
  35. package/dist/catalog/Catalog/QuickStartCatalogSection.d.ts +2 -2
  36. package/dist/catalog/Catalog/QuickStartCatalogToolbar.d.ts +2 -2
  37. package/dist/catalog/QuickStartCatalog.d.ts +2 -2
  38. package/dist/catalog/QuickStartTile.d.ts +2 -2
  39. package/dist/catalog/QuickStartTileDescription.d.ts +2 -2
  40. package/dist/catalog/QuickStartTileFooter.d.ts +2 -2
  41. package/dist/catalog/QuickStartTileFooterExternal.d.ts +2 -2
  42. package/dist/catalog/QuickStartTileHeader.d.ts +2 -2
  43. package/dist/catalog/Toolbar/QuickStartCatalogFilter.d.ts +2 -2
  44. package/dist/catalog/Toolbar/QuickStartCatalogFilterItems.d.ts +7 -7
  45. package/dist/controller/QuickStartConclusion.d.ts +2 -2
  46. package/dist/controller/QuickStartContent.d.ts +2 -2
  47. package/dist/controller/QuickStartFooter.d.ts +2 -2
  48. package/dist/controller/QuickStartIntroduction.d.ts +2 -2
  49. package/dist/controller/QuickStartTaskHeader.d.ts +2 -2
  50. package/dist/controller/QuickStartTaskHeaderList.d.ts +2 -2
  51. package/dist/controller/QuickStartTaskReview.d.ts +2 -2
  52. package/dist/controller/QuickStartTasks.d.ts +2 -2
  53. package/dist/index.es.js +489 -561
  54. package/dist/index.es.js.map +1 -1
  55. package/dist/index.js +500 -574
  56. package/dist/index.js.map +1 -1
  57. package/dist/quickstarts-base.css +61 -0
  58. package/dist/quickstarts-full.es.js +1963 -693
  59. package/dist/quickstarts-full.es.js.map +1 -1
  60. package/dist/quickstarts.css +61 -0
  61. package/dist/quickstarts.min.css +1 -1
  62. package/dist/utils/help-topic-context.d.ts +2 -2
  63. package/dist/utils/quick-start-context.d.ts +3 -3
  64. package/package.json +5 -6
  65. package/src/ConsoleInternal/components/markdown-view.tsx +112 -22
  66. package/src/ConsoleInternal/components/utils/camel-case-wrap.tsx +3 -3
  67. package/src/ConsoleInternal/components/utils/status-box.tsx +4 -4
  68. package/src/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.tsx +8 -15
  69. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +0 -1
  70. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/accordion-extension.spec.tsx +105 -0
  71. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/admonition-extension.spec.tsx +121 -0
  72. package/src/ConsoleShared/src/components/markdown-extensions/accordion-extension.tsx +22 -15
  73. package/src/ConsoleShared/src/components/markdown-extensions/accordion-render-extension.tsx +23 -9
  74. package/src/ConsoleShared/src/components/markdown-extensions/admonition-extension.tsx +19 -8
  75. package/src/ConsoleShared/src/components/markdown-extensions/code-extension.tsx +2 -2
  76. package/src/ConsoleShared/src/components/markdown-extensions/inline-clipboard-extension.tsx +3 -3
  77. package/src/ConsoleShared/src/components/markdown-extensions/multiline-clipboard-extension.tsx +3 -3
  78. package/src/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.tsx +5 -5
  79. package/src/ConsoleShared/src/components/modal/Modal.tsx +3 -3
  80. package/src/ConsoleShared/src/components/popper/Portal.tsx +5 -5
  81. package/src/ConsoleShared/src/components/popper/SimplePopper.tsx +15 -15
  82. package/src/ConsoleShared/src/components/spotlight/InteractiveSpotlight.tsx +6 -5
  83. package/src/ConsoleShared/src/components/spotlight/Spotlight.tsx +3 -3
  84. package/src/ConsoleShared/src/components/spotlight/StaticSpotlight.tsx +4 -3
  85. package/src/ConsoleShared/src/components/spotlight/spotlight.scss +63 -0
  86. package/src/ConsoleShared/src/components/status/GenericStatus.tsx +5 -5
  87. package/src/ConsoleShared/src/components/status/NotStartedIcon.tsx +0 -1
  88. package/src/ConsoleShared/src/components/status/PopoverStatus.tsx +4 -4
  89. package/src/ConsoleShared/src/components/status/Status.tsx +3 -11
  90. package/src/ConsoleShared/src/components/status/StatusIconAndText.tsx +6 -6
  91. package/src/ConsoleShared/src/components/status/icons.tsx +4 -8
  92. package/src/ConsoleShared/src/components/status/statuses.tsx +4 -5
  93. package/src/ConsoleShared/src/components/utils/FallbackImg.tsx +4 -4
  94. package/src/ConsoleShared/src/hooks/scroll.ts +4 -4
  95. package/src/ConsoleShared/src/hooks/useBoundingClientRect.ts +3 -3
  96. package/src/ConsoleShared/src/hooks/useForceRender.ts +2 -2
  97. package/src/ConsoleShared/src/hooks/useResizeObserver.ts +3 -6
  98. package/src/ConsoleShared/src/hooks/useScrollShadows.ts +4 -4
  99. package/src/ConsoleShared/src/utils/useCombineRefs.ts +4 -4
  100. package/src/HelpTopicDrawer.tsx +6 -6
  101. package/src/HelpTopicPanelContent.tsx +4 -4
  102. package/src/QuickStartCatalogPage.tsx +9 -9
  103. package/src/QuickStartCloseModal.tsx +3 -7
  104. package/src/QuickStartContainer.tsx +4 -4
  105. package/src/QuickStartController.tsx +11 -11
  106. package/src/QuickStartDrawer.tsx +6 -6
  107. package/src/QuickStartDrawerContent.tsx +6 -4
  108. package/src/QuickStartMarkdownView.tsx +3 -3
  109. package/src/QuickStartPanelContent.tsx +8 -8
  110. package/src/catalog/Catalog/QuickStartCatalogHeader.tsx +2 -2
  111. package/src/catalog/Catalog/QuickStartCatalogSection.tsx +2 -2
  112. package/src/catalog/Catalog/QuickStartCatalogToolbar.tsx +2 -2
  113. package/src/catalog/QuickStartCatalog.tsx +3 -3
  114. package/src/catalog/QuickStartTile.tsx +4 -4
  115. package/src/catalog/QuickStartTileDescription.tsx +4 -4
  116. package/src/catalog/QuickStartTileFooter.tsx +6 -6
  117. package/src/catalog/QuickStartTileFooterExternal.tsx +2 -5
  118. package/src/catalog/QuickStartTileHeader.tsx +2 -6
  119. package/src/catalog/Toolbar/QuickStartCatalogFilter.tsx +2 -2
  120. package/src/catalog/Toolbar/QuickStartCatalogFilterItems.tsx +17 -20
  121. package/src/catalog/__tests__/QuickStartCatalog.spec.tsx +0 -1
  122. package/src/catalog/__tests__/QuickStartTile.spec.tsx +0 -1
  123. package/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +1 -2
  124. package/src/controller/QuickStartConclusion.tsx +3 -3
  125. package/src/controller/QuickStartContent.tsx +2 -2
  126. package/src/controller/QuickStartFooter.tsx +10 -11
  127. package/src/controller/QuickStartIntroduction.tsx +5 -5
  128. package/src/controller/QuickStartTaskHeader.tsx +5 -5
  129. package/src/controller/QuickStartTaskHeaderList.tsx +2 -2
  130. package/src/controller/QuickStartTaskReview.tsx +4 -4
  131. package/src/controller/QuickStartTasks.tsx +5 -5
  132. package/src/controller/__tests__/QuickStartConclusion.spec.tsx +3 -3
  133. package/src/controller/__tests__/QuickStartContent.spec.tsx +2 -2
  134. package/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +2 -2
  135. package/src/controller/__tests__/QuickStartTaskReview.spec.tsx +2 -2
  136. package/src/utils/help-topic-context.tsx +7 -10
  137. package/src/utils/quick-start-context.tsx +11 -11
@@ -0,0 +1,121 @@
1
+ import { renderHook } from '@testing-library/react';
2
+ import useAdmonitionShowdownExtension from '../admonition-extension';
3
+ import { marked } from 'marked';
4
+
5
+ // Mock marked
6
+ jest.mock('marked', () => ({
7
+ marked: {
8
+ parseInline: jest.fn((text) => `<strong>${text}</strong>`),
9
+ },
10
+ }));
11
+
12
+ // Mock DOMPurify
13
+ jest.mock('dompurify', () => ({
14
+ sanitize: jest.fn((html) => html),
15
+ }));
16
+
17
+ describe('useAdmonitionShowdownExtension', () => {
18
+ beforeEach(() => {
19
+ jest.clearAllMocks();
20
+ });
21
+
22
+ it('should return a showdown extension with correct properties', () => {
23
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
24
+ const extension = result.current;
25
+
26
+ expect(extension.type).toBe('lang');
27
+ expect(extension.regex).toEqual(/\[(.+)]{{(admonition) ([\w-]+)}}/g);
28
+ expect(typeof extension.replace).toBe('function');
29
+ });
30
+
31
+ it('should match different admonition types', () => {
32
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
33
+ const { regex } = result.current;
34
+
35
+ const admonitionTypes = ['note', 'tip', 'important', 'warning', 'caution', 'custom-type'];
36
+
37
+ admonitionTypes.forEach((type) => {
38
+ const testText = `[Content for ${type}]{{admonition ${type}}}`;
39
+ // Reset regex state for global flag
40
+ regex.lastIndex = 0;
41
+ const matches = regex.exec(testText);
42
+
43
+ expect(matches).not.toBeNull();
44
+ if (matches) {
45
+ expect(matches[1]).toBe(`Content for ${type}`);
46
+ expect(matches[2]).toBe('admonition');
47
+ expect(matches[3]).toBe(type);
48
+ }
49
+ });
50
+ });
51
+
52
+ it('should not match malformed admonition syntax', () => {
53
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
54
+ const { regex } = result.current;
55
+
56
+ const malformedCases = [
57
+ 'Content]{{admonition note}}',
58
+ '[Content{{admonition note}}',
59
+ '[Content]{{admonition}}',
60
+ '[Content]{{notadmonition note}}',
61
+ ];
62
+
63
+ malformedCases.forEach((testCase) => {
64
+ expect(testCase.match(regex)).toBeNull();
65
+ });
66
+ });
67
+
68
+ it('should generate correct alert HTML structure', () => {
69
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
70
+ const { replace } = result.current;
71
+
72
+ const html = replace('[Test message]{{admonition note}}', 'Test message', 'admonition', 'note');
73
+
74
+ expect(html).toContain('pf-v6-c-alert');
75
+ expect(html).toContain('pf-m-info'); // note maps to info variant
76
+ expect(html).toContain('pf-m-inline');
77
+ expect(html).toContain('pfext-markdown-admonition');
78
+ expect(html).toContain('NOTE'); // uppercase title
79
+ });
80
+
81
+ it('should handle different admonition types with correct variants', () => {
82
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
83
+ const { replace } = result.current;
84
+
85
+ const testCases = [
86
+ { type: 'note', expectedClass: 'pf-m-info' },
87
+ { type: 'warning', expectedClass: 'pf-m-warning' },
88
+ { type: 'important', expectedClass: 'pf-m-danger' },
89
+ ];
90
+
91
+ testCases.forEach(({ type, expectedClass }) => {
92
+ const html = replace(`[Content]{{admonition ${type}}}`, 'Content', 'admonition', type);
93
+
94
+ expect(html).toContain(expectedClass);
95
+ expect(html).toContain(type.toUpperCase());
96
+ });
97
+ });
98
+
99
+ it('should process content through marked', () => {
100
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
101
+ const { replace } = result.current;
102
+
103
+ replace('[**Bold text**]{{admonition note}}', '**Bold text**', 'admonition', 'note');
104
+
105
+ expect(marked.parseInline).toHaveBeenCalledWith('**Bold text**');
106
+ });
107
+
108
+ it('should return original text for invalid cases', () => {
109
+ const { result } = renderHook(() => useAdmonitionShowdownExtension());
110
+ const { replace } = result.current;
111
+
112
+ // Missing content
113
+ const originalText = '[Content]{{admonition note}}';
114
+ const result1 = replace(originalText, '', 'admonition', 'note');
115
+ expect(result1).toBe(originalText);
116
+
117
+ // Wrong command
118
+ const result2 = replace(originalText, 'Content', 'not-admonition', 'note');
119
+ expect(result2).toBe(originalText);
120
+ });
121
+ });
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import { useMemo } from 'react';
2
2
  import {
3
3
  Accordion,
4
4
  AccordionItem,
@@ -8,34 +8,41 @@ import {
8
8
  import { renderToStaticMarkup } from 'react-dom/server';
9
9
  import { removeTemplateWhitespace } from './utils';
10
10
  import { ACCORDION_MARKDOWN_BUTTON_ID, ACCORDION_MARKDOWN_CONTENT_ID } from './const';
11
+ import { marked } from 'marked';
12
+
13
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
14
+ const DOMPurify = require('dompurify');
11
15
 
12
16
  const useAccordionShowdownExtension = () =>
13
- React.useMemo(
17
+ useMemo(
14
18
  () => ({
15
19
  type: 'lang',
16
- regex: /\[(.+)]{{(accordion) ("(.*?)")}}/g,
20
+ regex: /\[(.+)]{{(accordion) (&quot;(.*?)&quot;)}}/g,
17
21
  replace: (
18
22
  _text: string,
19
23
  accordionContent: string,
20
24
  _command: string,
25
+ _quotedHeading: string,
21
26
  accordionHeading: string,
22
27
  ): string => {
23
28
  const accordionId = String(accordionHeading).replace(/\s/g, '-');
24
29
 
30
+ // Process accordion content with markdown
31
+ const processedContent = marked.parseInline(accordionContent);
32
+ const sanitizedContent = DOMPurify.sanitize(processedContent);
33
+
25
34
  return removeTemplateWhitespace(
26
35
  renderToStaticMarkup(
27
- <>
28
- <Accordion asDefinitionList>
29
- <AccordionItem isExpanded={false}>
30
- <AccordionToggle id={`${ACCORDION_MARKDOWN_BUTTON_ID}-${accordionId}`}>
31
- {accordionHeading}
32
- </AccordionToggle>
33
- <AccordionContent id={`${ACCORDION_MARKDOWN_CONTENT_ID}-${accordionId}`}>
34
- {accordionContent}
35
- </AccordionContent>
36
- </AccordionItem>
37
- </Accordion>
38
- </>,
36
+ <Accordion>
37
+ <AccordionItem>
38
+ <AccordionToggle id={`${ACCORDION_MARKDOWN_BUTTON_ID}-${accordionId}`}>
39
+ {accordionHeading}
40
+ </AccordionToggle>
41
+ <AccordionContent id={`${ACCORDION_MARKDOWN_CONTENT_ID}-${accordionId}`} hidden>
42
+ <div dangerouslySetInnerHTML={{ __html: sanitizedContent }} />
43
+ </AccordionContent>
44
+ </AccordionItem>
45
+ </Accordion>,
39
46
  ),
40
47
  );
41
48
  },
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import { FC, useState } from 'react';
2
2
  import { useEventListener } from '../../hooks';
3
3
  import { ACCORDION_MARKDOWN_BUTTON_ID, ACCORDION_MARKDOWN_CONTENT_ID } from './const';
4
4
 
@@ -7,21 +7,35 @@ interface AccordionShowdownComponentProps {
7
7
  contentElement: HTMLElement;
8
8
  }
9
9
 
10
- const AccordionShowdownHandler: React.FC<AccordionShowdownComponentProps> = ({
10
+ const AccordionShowdownHandler: FC<AccordionShowdownComponentProps> = ({
11
11
  buttonElement,
12
12
  contentElement,
13
13
  }) => {
14
- const [expanded, setExpanded] = React.useState<boolean>(false);
14
+ const [expanded, setExpanded] = useState<boolean>(false);
15
15
 
16
16
  const handleClick = () => {
17
+ const newExpanded = !expanded;
17
18
  const expandedModifier = 'pf-m-expanded';
18
19
 
19
- buttonElement.className = `pf-v6-c-accordion__toggle ${!expanded ? expandedModifier : ''}`;
20
- contentElement.hidden = expanded;
21
- contentElement.className = `pf-v6-c-accordion__expanded-content ${
22
- !expanded ? expandedModifier : ''
20
+ // Find the accordion item element (parent of the button)
21
+ const accordionItem = buttonElement.closest('.pf-v6-c-accordion__item');
22
+
23
+ // Update button - both visual state and aria-expanded
24
+ buttonElement.className = `pf-v6-c-accordion__toggle ${newExpanded ? expandedModifier : ''}`;
25
+ buttonElement.setAttribute('aria-expanded', newExpanded.toString());
26
+
27
+ // Update content - both visual state and hidden attribute
28
+ contentElement.hidden = !newExpanded;
29
+ contentElement.className = `pf-v6-c-accordion__expandable-content ${
30
+ newExpanded ? expandedModifier : ''
23
31
  }`;
24
- setExpanded(!expanded);
32
+
33
+ // Update accordion item
34
+ if (accordionItem) {
35
+ accordionItem.className = `pf-v6-c-accordion__item ${newExpanded ? expandedModifier : ''}`;
36
+ }
37
+
38
+ setExpanded(newExpanded);
25
39
  };
26
40
 
27
41
  useEventListener(buttonElement, 'click', handleClick);
@@ -33,7 +47,7 @@ interface accordionRenderExtensionProps {
33
47
  docContext: Document;
34
48
  }
35
49
 
36
- const AccordionRenderExtension: React.FC<accordionRenderExtensionProps> = ({ docContext }) => {
50
+ const AccordionRenderExtension: FC<accordionRenderExtensionProps> = ({ docContext }) => {
37
51
  const buttonElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_BUTTON_ID}]`);
38
52
  const contentElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_CONTENT_ID}]`);
39
53
 
@@ -1,10 +1,13 @@
1
- import * as React from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { removeTemplateWhitespace } from './utils';
3
3
  import { renderToStaticMarkup } from 'react-dom/server';
4
4
  import { Alert } from '@patternfly/react-core';
5
5
  import LightbulbIcon from '@patternfly/react-icons/dist/js/icons/lightbulb-icon';
6
6
  import FireIcon from '@patternfly/react-icons/dist/js/icons/fire-icon';
7
- import QuickStartMarkdownView from '../../../../QuickStartMarkdownView';
7
+ import { marked } from 'marked';
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
10
+ const DOMPurify = require('dompurify');
8
11
 
9
12
  enum AdmonitionType {
10
13
  TIP = 'TIP',
@@ -24,7 +27,7 @@ const admonitionToAlertVariantMap = {
24
27
 
25
28
  const useAdmonitionShowdownExtension = () =>
26
29
  // const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
27
- React.useMemo(
30
+ useMemo(
28
31
  () => ({
29
32
  type: 'lang',
30
33
  regex: /\[(.+)]{{(admonition) ([\w-]+)}}/g,
@@ -33,15 +36,23 @@ const useAdmonitionShowdownExtension = () =>
33
36
  content: string,
34
37
  admonitionLabel: string,
35
38
  admonitionType: string,
36
- groupId: string,
37
39
  ): string => {
38
- if (!content || !admonitionLabel || !admonitionType || !groupId) {
40
+ if (!content || !admonitionLabel || !admonitionType) {
41
+ return text;
42
+ }
43
+ if (admonitionLabel !== 'admonition') {
39
44
  return text;
40
45
  }
41
46
  admonitionType = admonitionType.toUpperCase();
42
47
 
43
- const { variant, customIcon } = admonitionToAlertVariantMap[admonitionType];
44
- const mdContent = <QuickStartMarkdownView content={content} />;
48
+ // Process markdown content directly using marked
49
+ const processedContent = marked.parseInline(content);
50
+ const sanitizedContent = DOMPurify.sanitize(processedContent);
51
+
52
+ // Handle unknown admonition types by defaulting to NOTE
53
+ const admonitionConfig =
54
+ admonitionToAlertVariantMap[admonitionType] || admonitionToAlertVariantMap.NOTE;
55
+ const { variant, customIcon } = admonitionConfig;
45
56
  const pfAlert = (
46
57
  <Alert
47
58
  variant={variant}
@@ -50,7 +61,7 @@ const useAdmonitionShowdownExtension = () =>
50
61
  title={admonitionType}
51
62
  className="pfext-markdown-admonition"
52
63
  >
53
- {mdContent}
64
+ <div dangerouslySetInnerHTML={{ __html: sanitizedContent }} />
54
65
  </Alert>
55
66
  );
56
67
  return removeTemplateWhitespace(renderToStaticMarkup(pfAlert));
@@ -1,10 +1,10 @@
1
- import * as React from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { removeTemplateWhitespace } from './utils';
3
3
  import { renderToStaticMarkup } from 'react-dom/server';
4
4
  import { CodeBlock } from '@patternfly/react-core';
5
5
 
6
6
  const useCodeShowdownExtension = () =>
7
- React.useMemo(
7
+ useMemo(
8
8
  () => ({
9
9
  type: 'output',
10
10
  regex: /<pre><code>(.*?)\n?<\/code><\/pre>/g,
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import { useContext, useMemo } from 'react';
2
2
  import { QuickStartContext, QuickStartContextValues } from '@quickstarts/utils/quick-start-context';
3
3
  import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID } from './const';
4
4
  import { removeTemplateWhitespace } from './utils';
@@ -6,8 +6,8 @@ import { renderToStaticMarkup } from 'react-dom/server';
6
6
  import CopyIcon from '@patternfly/react-icons/dist/js/icons/copy-icon';
7
7
 
8
8
  const useInlineCopyClipboardShowdownExtension = () => {
9
- const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
10
- return React.useMemo(
9
+ const { getResource } = useContext<QuickStartContextValues>(QuickStartContext);
10
+ return useMemo(
11
11
  () => ({
12
12
  type: 'lang',
13
13
  regex: /`([^`](.*?)[^`])`{{copy}}/g,
@@ -1,13 +1,13 @@
1
1
  /* eslint-disable max-len */
2
- import * as React from 'react';
2
+ import { useContext, useMemo } from 'react';
3
3
  import { QuickStartContext, QuickStartContextValues } from '@quickstarts/utils/quick-start-context';
4
4
  import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID } from './const';
5
5
  import { renderToStaticMarkup } from 'react-dom/server';
6
6
  import CopyIcon from '@patternfly/react-icons/dist/js/icons/copy-icon';
7
7
 
8
8
  const useMultilineCopyClipboardShowdownExtension = () => {
9
- const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
10
- return React.useMemo(
9
+ const { getResource } = useContext<QuickStartContextValues>(QuickStartContext);
10
+ return useMemo(
11
11
  () => ({
12
12
  type: 'lang',
13
13
  regex: /```[\n]\s*((((?!```).)*?\n)+)\s*```{{copy}}/g,
@@ -1,16 +1,16 @@
1
- import * as React from 'react';
1
+ import { FC, useEffect, useState } from 'react';
2
2
  import { Spotlight } from '../spotlight';
3
3
 
4
4
  interface MarkdownHighlightExtensionProps {
5
5
  docContext: Document;
6
6
  rootSelector: string;
7
7
  }
8
- const MarkdownHighlightExtension: React.FC<MarkdownHighlightExtensionProps> = ({
8
+ const MarkdownHighlightExtension: FC<MarkdownHighlightExtensionProps> = ({
9
9
  docContext,
10
10
  rootSelector,
11
11
  }) => {
12
- const [selector, setSelector] = React.useState<string>(null);
13
- React.useEffect(() => {
12
+ const [selector, setSelector] = useState<string>(null);
13
+ useEffect(() => {
14
14
  const elements = docContext.querySelectorAll(`${rootSelector} [data-highlight]`);
15
15
  let timeoutId: NodeJS.Timeout;
16
16
  function startHighlight(e) {
@@ -29,7 +29,7 @@ const MarkdownHighlightExtension: React.FC<MarkdownHighlightExtensionProps> = ({
29
29
  elements && elements.forEach((elm) => elm.removeEventListener('click', startHighlight));
30
30
  };
31
31
  }, [docContext, rootSelector]);
32
- React.useEffect(() => {
32
+ useEffect(() => {
33
33
  const elements = docContext.querySelectorAll(`${rootSelector} [class^=data-highlight__]`);
34
34
  let timeoutId: NodeJS.Timeout;
35
35
  function startHighlight(e) {
@@ -1,13 +1,13 @@
1
- import * as React from 'react';
1
+ import { FC, Ref } from 'react';
2
2
  import { Modal as PfModal, ModalProps as PfModalProps } from '@patternfly/react-core/deprecated';
3
3
  import { css } from '@patternfly/react-styles';
4
4
 
5
5
  type ModalProps = {
6
6
  isFullScreen?: boolean;
7
- ref?: React.LegacyRef<PfModal>;
7
+ ref?: Ref<PfModal>;
8
8
  } & PfModalProps;
9
9
 
10
- const Modal: React.FC<ModalProps> = ({ isFullScreen = false, className, ...props }) => (
10
+ const Modal: FC<ModalProps> = ({ isFullScreen = false, className, ...props }) => (
11
11
  <PfModal
12
12
  {...props}
13
13
  className={css('pfext-modal', className)}
@@ -1,11 +1,11 @@
1
1
  import { useIsomorphicLayoutEffect } from '@patternfly/react-core';
2
- import * as React from 'react';
3
- import * as ReactDOM from 'react-dom';
2
+ import { useState, ReactNode } from 'react';
3
+ import { createPortal } from 'react-dom';
4
4
 
5
5
  type GetContainer = Element | null | undefined | (() => Element);
6
6
 
7
7
  interface PortalProps {
8
- children: React.ReactNode;
8
+ children: ReactNode;
9
9
  container?: GetContainer;
10
10
  }
11
11
 
@@ -13,13 +13,13 @@ const getContainer = (container: GetContainer): Element | null | undefined =>
13
13
  typeof container === 'function' ? container() : container;
14
14
 
15
15
  const Portal = ({ children, container }: PortalProps) => {
16
- const [containerNode, setContainerNode] = React.useState<Element>();
16
+ const [containerNode, setContainerNode] = useState<Element>();
17
17
 
18
18
  useIsomorphicLayoutEffect(() => {
19
19
  setContainerNode(getContainer(container) || document.body);
20
20
  }, [container]);
21
21
 
22
- return containerNode ? ReactDOM.createPortal(children, containerNode) : null;
22
+ return containerNode ? createPortal(children, containerNode) : null;
23
23
  };
24
24
 
25
25
  export default Portal;
@@ -1,25 +1,25 @@
1
- import * as React from 'react';
1
+ import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import Portal from './Portal';
3
3
 
4
4
  interface SimplePopperProps {
5
- children: React.ReactNode;
5
+ children: ReactNode;
6
6
  }
7
7
 
8
8
  const SimplePopper = ({ children }: SimplePopperProps) => {
9
9
  const openProp = true;
10
- const nodeRef = React.useRef<Element>();
11
- const popperRef = React.useRef(null);
12
- const [isOpen, setOpenState] = React.useState(openProp);
10
+ const nodeRef = useRef<Element>(null);
11
+ const popperRef = useRef(null);
12
+ const [isOpen, setOpenState] = useState(openProp);
13
13
 
14
- const setOpen = React.useCallback((newOpen: boolean) => {
14
+ const setOpen = useCallback((newOpen: boolean) => {
15
15
  setOpenState(newOpen);
16
16
  }, []);
17
17
 
18
- React.useEffect(() => {
18
+ useEffect(() => {
19
19
  setOpen(openProp);
20
20
  }, [openProp, setOpen]);
21
21
 
22
- const onKeyDown = React.useCallback(
22
+ const onKeyDown = useCallback(
23
23
  (e: KeyboardEvent) => {
24
24
  if (e.keyCode === 27) {
25
25
  setOpen(false);
@@ -28,7 +28,7 @@ const SimplePopper = ({ children }: SimplePopperProps) => {
28
28
  [setOpen],
29
29
  );
30
30
 
31
- const onClickOutside = React.useCallback(
31
+ const onClickOutside = useCallback(
32
32
  (e: MouseEvent) => {
33
33
  if (!nodeRef.current || (e.target instanceof Node && !nodeRef.current.contains(e.target))) {
34
34
  setOpen(false);
@@ -37,7 +37,7 @@ const SimplePopper = ({ children }: SimplePopperProps) => {
37
37
  [setOpen],
38
38
  );
39
39
 
40
- const destroy = React.useCallback(() => {
40
+ const destroy = useCallback(() => {
41
41
  if (popperRef.current) {
42
42
  popperRef.current.destroy();
43
43
  document.removeEventListener('keydown', onKeyDown, true);
@@ -46,7 +46,7 @@ const SimplePopper = ({ children }: SimplePopperProps) => {
46
46
  }
47
47
  }, [onClickOutside, onKeyDown]);
48
48
 
49
- const initialize = React.useCallback(() => {
49
+ const initialize = useCallback(() => {
50
50
  if (!nodeRef.current || !isOpen) {
51
51
  return;
52
52
  }
@@ -54,7 +54,7 @@ const SimplePopper = ({ children }: SimplePopperProps) => {
54
54
  destroy();
55
55
  }, [isOpen, destroy]);
56
56
 
57
- const nodeRefCallback = React.useCallback(
57
+ const nodeRefCallback = useCallback(
58
58
  (node) => {
59
59
  nodeRef.current = node;
60
60
  initialize();
@@ -62,18 +62,18 @@ const SimplePopper = ({ children }: SimplePopperProps) => {
62
62
  [initialize],
63
63
  );
64
64
 
65
- React.useEffect(() => {
65
+ useEffect(() => {
66
66
  initialize();
67
67
  }, [initialize]);
68
68
 
69
- React.useEffect(
69
+ useEffect(
70
70
  () => () => {
71
71
  destroy();
72
72
  },
73
73
  [destroy],
74
74
  );
75
75
 
76
- React.useEffect(() => {
76
+ useEffect(() => {
77
77
  if (!isOpen) {
78
78
  destroy();
79
79
  }
@@ -1,4 +1,5 @@
1
- import * as React from 'react';
1
+ import './spotlight.scss';
2
+ import { CSSProperties, FC, useEffect, useState } from 'react';
2
3
  import { Portal, SimplePopper } from '../popper';
3
4
 
4
5
  interface InteractiveSpotlightProps {
@@ -15,9 +16,9 @@ const isInViewport = (elementToCheck: Element) => {
15
16
  );
16
17
  };
17
18
 
18
- const InteractiveSpotlight: React.FC<InteractiveSpotlightProps> = ({ element }) => {
19
+ const InteractiveSpotlight: FC<InteractiveSpotlightProps> = ({ element }) => {
19
20
  const { top, bottom, left, right, height, width } = element.getBoundingClientRect();
20
- const style: React.CSSProperties = {
21
+ const style: CSSProperties = {
21
22
  height,
22
23
  width,
23
24
  top,
@@ -25,9 +26,9 @@ const InteractiveSpotlight: React.FC<InteractiveSpotlightProps> = ({ element })
25
26
  bottom,
26
27
  right,
27
28
  };
28
- const [clicked, setClicked] = React.useState(false);
29
+ const [clicked, setClicked] = useState(false);
29
30
 
30
- React.useEffect(() => {
31
+ useEffect(() => {
31
32
  if (!clicked) {
32
33
  if (!isInViewport(element)) {
33
34
  element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import { FC, useMemo } from 'react';
2
2
  import InteractiveSpotlight from './InteractiveSpotlight';
3
3
  import StaticSpotlight from './StaticSpotlight';
4
4
 
@@ -7,9 +7,9 @@ interface SpotlightProps {
7
7
  interactive?: boolean;
8
8
  }
9
9
 
10
- const Spotlight: React.FC<SpotlightProps> = ({ selector, interactive }) => {
10
+ const Spotlight: FC<SpotlightProps> = ({ selector, interactive }) => {
11
11
  // if target element is a hidden one return null
12
- const element = React.useMemo(() => {
12
+ const element = useMemo(() => {
13
13
  const highlightElement = document.querySelector(selector);
14
14
  let hiddenElement = highlightElement;
15
15
  while (hiddenElement) {
@@ -1,4 +1,5 @@
1
- import * as React from 'react';
1
+ import './spotlight.scss';
2
+ import { CSSProperties, FC } from 'react';
2
3
  import { useBoundingClientRect } from '../../hooks';
3
4
  import Portal from '../popper/Portal';
4
5
 
@@ -6,9 +7,9 @@ interface StaticSpotlightProps {
6
7
  element: Element;
7
8
  }
8
9
 
9
- const StaticSpotlight: React.FC<StaticSpotlightProps> = ({ element }) => {
10
+ const StaticSpotlight: FC<StaticSpotlightProps> = ({ element }) => {
10
11
  const clientRect = useBoundingClientRect(element as HTMLElement);
11
- const style: React.CSSProperties = clientRect
12
+ const style: CSSProperties = clientRect
12
13
  ? {
13
14
  top: clientRect.top,
14
15
  left: clientRect.left,
@@ -0,0 +1,63 @@
1
+ @keyframes pfext-spotlight-expand {
2
+ 0% {
3
+ outline-offset: -4px;
4
+ outline-width: 4px;
5
+ opacity: 1;
6
+ }
7
+ 100% {
8
+ outline-offset: 21px;
9
+ outline-width: 12px;
10
+ opacity: 0;
11
+ }
12
+ }
13
+
14
+ @keyframes pfext-spotlight-fade-in {
15
+ 0% {
16
+ opacity: 0;
17
+ }
18
+ 100% {
19
+ opacity: 1;
20
+ }
21
+ }
22
+
23
+ @keyframes pfext-spotlight-fade-out {
24
+ 0% {
25
+ opacity: 1;
26
+ }
27
+ 100% {
28
+ opacity: 0;
29
+ }
30
+ }
31
+
32
+ .pfext-spotlight {
33
+ pointer-events: none;
34
+ position: absolute;
35
+ &__with-backdrop {
36
+ mix-blend-mode: hard-light;
37
+ }
38
+ &__element-highlight-noanimate {
39
+ border: var(--pf-t--global--border--width--strong) solid var(--pf-t--global--border--color--brand--default);
40
+ background-color: var(--pf-t--color--gray--40);
41
+ z-index: 9999;
42
+ }
43
+ &__element-highlight-animate {
44
+ pointer-events: none;
45
+ position: absolute;
46
+ box-shadow: inset 0px 0px 0px 4px var(--pf-t--global--color--brand--default);
47
+ opacity: 0;
48
+ animation: 0.4s pfext-spotlight-fade-in 0s ease-in-out, 5s pfext-spotlight-fade-out 12.8s ease-in-out;
49
+ animation-fill-mode: forwards;
50
+ &::after {
51
+ content: '';
52
+ position: absolute;
53
+ left: 0;
54
+ right: 0;
55
+ top: 0;
56
+ bottom: 0;
57
+ animation: 1.2s pfext-spotlight-expand 1.6s ease-out;
58
+ animation-fill-mode: forwards;
59
+ outline: 4px solid var(--pf-t--global--color--brand--default);
60
+ outline-offset: -4px;
61
+ }
62
+ }
63
+ }