@patternfly/quickstarts 2.2.2 → 2.3.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 (195) hide show
  1. package/README.md +4 -4
  2. package/dist/HelpTopicDrawer.d.ts +8 -2
  3. package/dist/QuickStartDrawer.d.ts +21 -2
  4. package/dist/controller/QuickStartTaskHeader.d.ts +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.es.js +104 -4
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.js +104 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/patternfly-docs/quick-starts/design-guidelines/design-guidelines.md +105 -0
  11. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements copy.png +0 -0
  12. package/dist/patternfly-docs/quick-starts/design-guidelines/img/card-elements.png +0 -0
  13. package/dist/patternfly-docs/quick-starts/design-guidelines/img/catalog-elements.png +0 -0
  14. package/dist/patternfly-docs/quick-starts/design-guidelines/img/check-your-work.png +0 -0
  15. package/dist/patternfly-docs/quick-starts/design-guidelines/img/introduction-screen.png +0 -0
  16. package/dist/patternfly-docs/quick-starts/design-guidelines/img/mixed-catalog.png +0 -0
  17. package/dist/patternfly-docs/quick-starts/design-guidelines/img/prerequisites.png +0 -0
  18. package/dist/patternfly-docs/quick-starts/design-guidelines/img/qs-context.png +0 -0
  19. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-elements.png +0 -0
  20. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel-resized.png +0 -0
  21. package/dist/patternfly-docs/quick-starts/design-guidelines/img/side-panel.png +0 -0
  22. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-no.png +0 -0
  23. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task-yes.png +0 -0
  24. package/dist/patternfly-docs/quick-starts/design-guidelines/img/task.png +0 -0
  25. package/dist/patternfly-docs/quick-starts/examples/Basic.jsx +73 -0
  26. package/dist/patternfly-docs/quick-starts/examples/HelpTopic.jsx +53 -0
  27. package/dist/patternfly-docs/quick-starts/examples/about.md +77 -0
  28. package/dist/patternfly-docs/quick-starts/examples/basic.md +27 -0
  29. package/dist/patternfly-docs/quick-starts/examples/example-data/example-help-topics.js +173 -0
  30. package/dist/patternfly-docs/quick-starts/examples/example-data/example-quickstarts.js +215 -0
  31. package/dist/patternfly-docs/quick-starts/examples/example-data/index.js +15 -0
  32. package/dist/patternfly-docs/quick-starts/examples/help-topics.md +25 -0
  33. package/dist/patternfly-docs/quick-starts/examples/img/catalog.png +0 -0
  34. package/dist/patternfly-docs/quick-starts/examples/img/help-topic.png +0 -0
  35. package/dist/patternfly-docs/quick-starts/examples/img/side-panel.png +0 -0
  36. package/dist/quickstarts-full.es.js +104 -4
  37. package/dist/quickstarts-full.es.js.map +1 -1
  38. package/dist/utils/asciidoc-procedure-parser.d.ts +12 -0
  39. package/package.json +11 -4
  40. package/src/ConsoleInternal/components/_icon-and-text.scss +14 -0
  41. package/src/ConsoleInternal/components/_markdown-view.scss +19 -0
  42. package/src/ConsoleInternal/components/catalog/_catalog.scss +390 -0
  43. package/src/ConsoleInternal/components/markdown-view.tsx +305 -0
  44. package/src/ConsoleInternal/components/utils/_status-box.scss +58 -0
  45. package/src/ConsoleInternal/components/utils/camel-case-wrap.tsx +33 -0
  46. package/src/ConsoleInternal/components/utils/index.tsx +3 -0
  47. package/src/ConsoleInternal/components/utils/router.ts +47 -0
  48. package/src/ConsoleInternal/components/utils/status-box.tsx +94 -0
  49. package/src/ConsoleInternal/module/k8s/types.ts +53 -0
  50. package/src/ConsoleShared/index.ts +1 -0
  51. package/src/ConsoleShared/src/components/index.ts +7 -0
  52. package/src/ConsoleShared/src/components/layout/PageLayout.scss +29 -0
  53. package/src/ConsoleShared/src/components/markdown-extensions/MarkdownCopyClipboard.tsx +93 -0
  54. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +25 -0
  55. package/src/ConsoleShared/src/components/markdown-extensions/__tests__/test-data.ts +5 -0
  56. package/src/ConsoleShared/src/components/markdown-extensions/admonition-extension.tsx +66 -0
  57. package/src/ConsoleShared/src/components/markdown-extensions/code-extension.tsx +25 -0
  58. package/src/ConsoleShared/src/components/markdown-extensions/const.ts +3 -0
  59. package/src/ConsoleShared/src/components/markdown-extensions/index.ts +5 -0
  60. package/src/ConsoleShared/src/components/markdown-extensions/inline-clipboard-extension.tsx +45 -0
  61. package/src/ConsoleShared/src/components/markdown-extensions/multiline-clipboard-extension.tsx +50 -0
  62. package/src/ConsoleShared/src/components/markdown-extensions/showdown-extension.scss +52 -0
  63. package/src/ConsoleShared/src/components/markdown-extensions/utils.ts +3 -0
  64. package/src/ConsoleShared/src/components/markdown-highlight-extension/MarkdownHighlightExtension.tsx +64 -0
  65. package/src/ConsoleShared/src/components/markdown-highlight-extension/highlight-consts.ts +9 -0
  66. package/src/ConsoleShared/src/components/markdown-highlight-extension/index.ts +1 -0
  67. package/src/ConsoleShared/src/components/modal/Modal.scss +3 -0
  68. package/src/ConsoleShared/src/components/modal/Modal.tsx +19 -0
  69. package/src/ConsoleShared/src/components/modal/index.ts +1 -0
  70. package/src/ConsoleShared/src/components/popper/Portal.tsx +23 -0
  71. package/src/ConsoleShared/src/components/popper/SimplePopper.tsx +90 -0
  72. package/src/ConsoleShared/src/components/popper/index.ts +2 -0
  73. package/src/ConsoleShared/src/components/spotlight/InteractiveSpotlight.tsx +58 -0
  74. package/src/ConsoleShared/src/components/spotlight/Spotlight.tsx +35 -0
  75. package/src/ConsoleShared/src/components/spotlight/StaticSpotlight.tsx +32 -0
  76. package/src/ConsoleShared/src/components/spotlight/index.ts +1 -0
  77. package/src/ConsoleShared/src/components/spotlight/spotlight.scss +63 -0
  78. package/src/ConsoleShared/src/components/status/GenericStatus.tsx +33 -0
  79. package/src/ConsoleShared/src/components/status/NotStartedIcon.tsx +27 -0
  80. package/src/ConsoleShared/src/components/status/PopoverStatus.tsx +42 -0
  81. package/src/ConsoleShared/src/components/status/Status.tsx +38 -0
  82. package/src/ConsoleShared/src/components/status/StatusIconAndText.tsx +42 -0
  83. package/src/ConsoleShared/src/components/status/icons.tsx +77 -0
  84. package/src/ConsoleShared/src/components/status/index.tsx +1 -0
  85. package/src/ConsoleShared/src/components/status/statuses.tsx +36 -0
  86. package/src/ConsoleShared/src/components/status/types.ts +7 -0
  87. package/src/ConsoleShared/src/components/utils/FallbackImg.tsx +20 -0
  88. package/src/ConsoleShared/src/components/utils/index.ts +1 -0
  89. package/src/ConsoleShared/src/constants/index.ts +1 -0
  90. package/src/ConsoleShared/src/constants/ui.ts +1 -0
  91. package/src/ConsoleShared/src/hooks/index.ts +6 -0
  92. package/src/ConsoleShared/src/hooks/scroll.ts +52 -0
  93. package/src/ConsoleShared/src/hooks/useBoundingClientRect.ts +18 -0
  94. package/src/ConsoleShared/src/hooks/useEventListener.ts +14 -0
  95. package/src/ConsoleShared/src/hooks/useForceRender.ts +6 -0
  96. package/src/ConsoleShared/src/hooks/useResizeObserver.ts +20 -0
  97. package/src/ConsoleShared/src/hooks/useScrollShadows.ts +45 -0
  98. package/src/ConsoleShared/src/index.ts +4 -0
  99. package/src/ConsoleShared/src/utils/index.ts +1 -0
  100. package/src/ConsoleShared/src/utils/useCombineRefs.ts +17 -0
  101. package/src/HelpTopicDrawer.tsx +124 -0
  102. package/src/HelpTopicPanelContent.tsx +152 -0
  103. package/src/QuickStartCatalogPage.tsx +190 -0
  104. package/src/QuickStartCloseModal.tsx +47 -0
  105. package/src/QuickStartController.tsx +113 -0
  106. package/src/QuickStartDrawer.scss +11 -0
  107. package/src/QuickStartDrawer.tsx +265 -0
  108. package/src/QuickStartMarkdownView.tsx +75 -0
  109. package/src/QuickStartPanelContent.scss +46 -0
  110. package/src/QuickStartPanelContent.tsx +153 -0
  111. package/src/__tests__/quick-start-utils.spec.tsx +16 -0
  112. package/src/catalog/Catalog/QuickStartCatalogHeader.tsx +18 -0
  113. package/src/catalog/Catalog/QuickStartCatalogSection.tsx +9 -0
  114. package/src/catalog/Catalog/QuickStartCatalogToolbar.tsx +12 -0
  115. package/src/catalog/Catalog/index.ts +3 -0
  116. package/src/catalog/QuickStartCatalog.scss +8 -0
  117. package/src/catalog/QuickStartCatalog.tsx +42 -0
  118. package/src/catalog/QuickStartTile.scss +11 -0
  119. package/src/catalog/QuickStartTile.tsx +105 -0
  120. package/src/catalog/QuickStartTileDescription.scss +29 -0
  121. package/src/catalog/QuickStartTileDescription.tsx +79 -0
  122. package/src/catalog/QuickStartTileFooter.tsx +101 -0
  123. package/src/catalog/QuickStartTileFooterExternal.tsx +40 -0
  124. package/src/catalog/QuickStartTileHeader.scss +12 -0
  125. package/src/catalog/QuickStartTileHeader.tsx +77 -0
  126. package/src/catalog/Toolbar/QuickStartCatalogFilter.scss +25 -0
  127. package/src/catalog/Toolbar/QuickStartCatalogFilter.tsx +34 -0
  128. package/src/catalog/Toolbar/QuickStartCatalogFilterItems.tsx +199 -0
  129. package/src/catalog/__tests__/QuickStartCatalog.spec.tsx +35 -0
  130. package/src/catalog/__tests__/QuickStartTile.spec.tsx +38 -0
  131. package/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +44 -0
  132. package/src/catalog/index.ts +9 -0
  133. package/src/controller/QuickStartConclusion.tsx +63 -0
  134. package/src/controller/QuickStartContent.scss +12 -0
  135. package/src/controller/QuickStartContent.tsx +72 -0
  136. package/src/controller/QuickStartFooter.scss +13 -0
  137. package/src/controller/QuickStartFooter.tsx +128 -0
  138. package/src/controller/QuickStartIntroduction.scss +35 -0
  139. package/src/controller/QuickStartIntroduction.tsx +66 -0
  140. package/src/controller/QuickStartTaskHeader.scss +58 -0
  141. package/src/controller/QuickStartTaskHeader.tsx +116 -0
  142. package/src/controller/QuickStartTaskHeaderList.scss +17 -0
  143. package/src/controller/QuickStartTaskHeaderList.tsx +35 -0
  144. package/src/controller/QuickStartTaskReview.scss +30 -0
  145. package/src/controller/QuickStartTaskReview.tsx +81 -0
  146. package/src/controller/QuickStartTasks.scss +89 -0
  147. package/src/controller/QuickStartTasks.tsx +75 -0
  148. package/src/controller/__tests__/QuickStartConclusion.spec.tsx +95 -0
  149. package/src/controller/__tests__/QuickStartContent.spec.tsx +52 -0
  150. package/src/controller/__tests__/QuickStartFooter.spec.tsx +148 -0
  151. package/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +56 -0
  152. package/src/controller/__tests__/QuickStartTaskReview.spec.tsx +45 -0
  153. package/src/controller/__tests__/QuickStartTasks.spec.tsx +81 -0
  154. package/src/data/mocks/json/explore-pipeline-quickstart.ts +66 -0
  155. package/src/data/mocks/json/explore-serverless-quickstart.ts +90 -0
  156. package/src/data/mocks/json/monitor-sampleapp-quickstart.ts +77 -0
  157. package/src/data/mocks/json/tour-icons.ts +3 -0
  158. package/src/data/mocks/yamls/add-healthchecks-quickstart.yaml +67 -0
  159. package/src/data/mocks/yamls/explore-pipeline-quickstart.yaml +57 -0
  160. package/src/data/mocks/yamls/explore-serverless-quickstart.yaml +83 -0
  161. package/src/data/mocks/yamls/install-associate-pipeline-quickstart.yaml +74 -0
  162. package/src/data/mocks/yamls/monitor-sampleapp-quickstart.yaml +66 -0
  163. package/src/data/mocks/yamls/sample-application-quickstart.yaml +97 -0
  164. package/src/data/mocks/yamls/serverless-application-quickstart.yaml +141 -0
  165. package/src/data/quick-start-test-data.ts +10 -0
  166. package/src/data/test-utils.ts +11 -0
  167. package/src/declaration.d.ts +2 -0
  168. package/src/index.ts +17 -0
  169. package/src/locales/en/quickstart.json +46 -0
  170. package/src/styles/_base.scss +54 -0
  171. package/src/styles/_dark-custom-override.scss +62 -0
  172. package/src/styles/legacy-bootstrap/README.md +21 -0
  173. package/src/styles/legacy-bootstrap/_code.scss +44 -0
  174. package/src/styles/legacy-bootstrap/_tables.scss +38 -0
  175. package/src/styles/legacy-bootstrap/_type.scss +90 -0
  176. package/src/styles/legacy-bootstrap/_variables.scss +48 -0
  177. package/src/styles/legacy-bootstrap.scss +5 -0
  178. package/src/styles/patternfly-global-entry.ts +1 -0
  179. package/src/styles/patternfly-global.scss +28 -0
  180. package/src/styles/patternfly-nested-entry.ts +1 -0
  181. package/src/styles/patternfly-nested.scss +18 -0
  182. package/src/styles/quickstarts-standalone-entry.ts +1 -0
  183. package/src/styles/quickstarts-standalone.scss +7 -0
  184. package/src/styles/style.scss +12 -0
  185. package/src/styles/vendor-entry.ts +1 -0
  186. package/src/styles/vendor.scss +7 -0
  187. package/src/utils/PluralResolver.ts +356 -0
  188. package/src/utils/asciidoc-procedure-parser.ts +132 -0
  189. package/src/utils/const.ts +10 -0
  190. package/src/utils/help-topic-context.tsx +74 -0
  191. package/src/utils/help-topic-types.ts +16 -0
  192. package/src/utils/quick-start-context.tsx +477 -0
  193. package/src/utils/quick-start-types.ts +72 -0
  194. package/src/utils/quick-start-utils.ts +92 -0
  195. package/src/utils/useLocalStorage.ts +38 -0
@@ -0,0 +1,93 @@
1
+ import * as React from 'react';
2
+ import { Tooltip } from '@patternfly/react-core';
3
+ import { QuickStartContext, QuickStartContextValues } from '@quickstarts/utils/quick-start-context';
4
+ import { useEventListener } from '../../hooks';
5
+ import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID } from './const';
6
+
7
+ type CopyClipboardProps = {
8
+ element: HTMLElement;
9
+ rootSelector: string;
10
+ docContext: HTMLDocument;
11
+ };
12
+
13
+ export const CopyClipboard: React.FC<CopyClipboardProps> = ({
14
+ element,
15
+ rootSelector,
16
+ docContext,
17
+ }) => {
18
+ const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
19
+ const [showSuccessContent, setShowSuccessContent] = React.useState<boolean>(false);
20
+ const textToCopy = React.useMemo(() => {
21
+ const copyTextId = element.getAttribute(MARKDOWN_COPY_BUTTON_ID);
22
+ return (docContext.querySelector(
23
+ `${rootSelector} [${MARKDOWN_SNIPPET_ID}="${copyTextId}"]`,
24
+ ) as HTMLElement).innerText;
25
+ }, [element, docContext, rootSelector]);
26
+
27
+ useEventListener(
28
+ element,
29
+ 'click',
30
+ React.useCallback(() => {
31
+ navigator.clipboard
32
+ .writeText(textToCopy)
33
+ .then(() => {
34
+ setShowSuccessContent(true);
35
+ })
36
+ .catch(() => {});
37
+ }, [textToCopy]),
38
+ );
39
+
40
+ useEventListener(
41
+ element,
42
+ 'mouseleave',
43
+ React.useCallback(() => {
44
+ setShowSuccessContent(false);
45
+ }, []),
46
+ );
47
+
48
+ return showSuccessContent ? (
49
+ <Tooltip
50
+ key="after-copy"
51
+ isVisible
52
+ reference={() => element as HTMLElement}
53
+ content={getResource('Successfully copied to clipboard!')}
54
+ className="pfext-quick-start__base"
55
+ />
56
+ ) : (
57
+ <Tooltip
58
+ key="before-copy"
59
+ reference={() => element as HTMLElement}
60
+ content={getResource('Copy to clipboard')}
61
+ className="pfext-quick-start__base"
62
+ />
63
+ );
64
+ };
65
+
66
+ type MarkdownCopyClipboardProps = {
67
+ docContext: HTMLDocument;
68
+ rootSelector: string;
69
+ };
70
+
71
+ const MarkdownCopyClipboard: React.FC<MarkdownCopyClipboardProps> = ({
72
+ docContext,
73
+ rootSelector,
74
+ }) => {
75
+ const elements = docContext.querySelectorAll(`${rootSelector} [${MARKDOWN_COPY_BUTTON_ID}]`);
76
+ return elements.length > 0 ? (
77
+ <>
78
+ {Array.from(elements).map((elm) => {
79
+ const attributeValue = elm.getAttribute(MARKDOWN_COPY_BUTTON_ID);
80
+ return (
81
+ <CopyClipboard
82
+ key={attributeValue}
83
+ element={elm as HTMLElement}
84
+ rootSelector={rootSelector}
85
+ docContext={docContext}
86
+ />
87
+ );
88
+ })}
89
+ </>
90
+ ) : null;
91
+ };
92
+
93
+ export default MarkdownCopyClipboard;
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { shallow } from 'enzyme';
3
+ import MarkdownCopyClipboard, { CopyClipboard } from '../MarkdownCopyClipboard';
4
+ import { htmlDocumentForCopyClipboard } from './test-data';
5
+
6
+ describe('MarkdownCopyClipboard', () => {
7
+ beforeAll(() => {
8
+ document.body.innerHTML = htmlDocumentForCopyClipboard;
9
+ });
10
+ it('should render null if no element is found', () => {
11
+ const wrapper = shallow(
12
+ <MarkdownCopyClipboard docContext={document} rootSelector="#copy-markdown-3" />,
13
+ );
14
+ expect(wrapper.isEmptyRender()).toBe(true);
15
+ expect(wrapper.find(CopyClipboard).exists()).toBe(false);
16
+ });
17
+
18
+ it('should render null if no element is found', () => {
19
+ const wrapper = shallow(
20
+ <MarkdownCopyClipboard docContext={document} rootSelector="#copy-markdown-1" />,
21
+ );
22
+ expect(wrapper.isEmptyRender()).toBe(false);
23
+ expect(wrapper.find(CopyClipboard).exists()).toBe(true);
24
+ });
25
+ });
@@ -0,0 +1,5 @@
1
+ import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID, MARKDOWN_EXECUTE_BUTTON_ID } from '../const';
2
+
3
+ export const htmlDocumentForCopyClipboard = `<div id="copy-markdown-1"><div ${MARKDOWN_SNIPPET_ID}="1234">some test data for testing</div><button ${MARKDOWN_COPY_BUTTON_ID}="1234"</button><div ${MARKDOWN_SNIPPET_ID}="12354">some test data for testing</div><button ${MARKDOWN_COPY_BUTTON_ID}="12354"</button></div>`;
4
+
5
+ export const htmlDocumentForExecuteButton = `<div id="execute-markdown-1"><div ${MARKDOWN_SNIPPET_ID}="1234">some test data for testing</div><button ${MARKDOWN_EXECUTE_BUTTON_ID}="1234"</button><div ${MARKDOWN_SNIPPET_ID}="12354">some test data for testing</div><button ${MARKDOWN_EXECUTE_BUTTON_ID}="12354"</button></div>`;
@@ -0,0 +1,66 @@
1
+ import * as React from 'react';
2
+ import { removeTemplateWhitespace } from './utils';
3
+ import { renderToStaticMarkup } from 'react-dom/server';
4
+ import { Alert } from '@patternfly/react-core';
5
+ import LightbulbIcon from '@patternfly/react-icons/dist/js/icons/lightbulb-icon';
6
+ import FireIcon from '@patternfly/react-icons/dist/js/icons/fire-icon';
7
+ import './showdown-extension.scss';
8
+
9
+ enum AdmonitionType {
10
+ TIP = 'TIP',
11
+ NOTE = 'NOTE',
12
+ IMPORTANT = 'IMPORTANT',
13
+ WARNING = 'WARNING',
14
+ CAUTION = 'CAUTION',
15
+ }
16
+
17
+ const admonitionToAlertVariantMap = {
18
+ [AdmonitionType.NOTE]: { variant: 'info' },
19
+ [AdmonitionType.TIP]: { variant: 'default', customIcon: <LightbulbIcon /> },
20
+ [AdmonitionType.IMPORTANT]: { variant: 'danger' },
21
+ [AdmonitionType.CAUTION]: { variant: 'warning', customIcon: <FireIcon /> },
22
+ [AdmonitionType.WARNING]: { variant: 'warning' },
23
+ };
24
+
25
+ const useAdmonitionShowdownExtension = () => {
26
+ // const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
27
+ return React.useMemo(
28
+ () => ({
29
+ type: 'lang',
30
+ regex: /\[(.+)]{{(admonition) ([\w-]+)}}/g,
31
+ replace: (
32
+ text: string,
33
+ content: string,
34
+ admonitionLabel: string,
35
+ admonitionType: string,
36
+ groupId: string,
37
+ ): string => {
38
+ if (!content || !admonitionLabel || !admonitionType || !groupId) {
39
+ return text;
40
+ }
41
+ admonitionType = admonitionType.toUpperCase();
42
+
43
+ const { variant, customIcon } = admonitionToAlertVariantMap[admonitionType];
44
+ const style =
45
+ admonitionType === AdmonitionType.CAUTION ? { backgroundColor: '#ec7a0915' } : {};
46
+
47
+ const pfAlert = (
48
+ <Alert
49
+ variant={variant}
50
+ customIcon={customIcon && customIcon}
51
+ isInline
52
+ title={admonitionType}
53
+ className="pfext-markdown-admonition"
54
+ style={style}
55
+ >
56
+ {content}
57
+ </Alert>
58
+ );
59
+ return removeTemplateWhitespace(renderToStaticMarkup(pfAlert));
60
+ },
61
+ }),
62
+ [],
63
+ );
64
+ };
65
+
66
+ export default useAdmonitionShowdownExtension;
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { removeTemplateWhitespace } from './utils';
3
+ import { renderToStaticMarkup } from 'react-dom/server';
4
+ import { CodeBlock } from '@patternfly/react-core';
5
+ import './showdown-extension.scss';
6
+
7
+ const useCodeShowdownExtension = () => {
8
+ return React.useMemo(
9
+ () => ({
10
+ type: 'output',
11
+ regex: /<pre><code>(.*?)\n?<\/code><\/pre>/g,
12
+ replace: (text: string, content: string): string => {
13
+ if (!content) {
14
+ return text;
15
+ }
16
+ const pfCodeBlock = <CodeBlock>{content}</CodeBlock>;
17
+
18
+ return removeTemplateWhitespace(renderToStaticMarkup(pfCodeBlock));
19
+ },
20
+ }),
21
+ [],
22
+ );
23
+ };
24
+
25
+ export default useCodeShowdownExtension;
@@ -0,0 +1,3 @@
1
+ export const MARKDOWN_COPY_BUTTON_ID = 'data-copy-for';
2
+ export const MARKDOWN_EXECUTE_BUTTON_ID = 'data-execute-for';
3
+ export const MARKDOWN_SNIPPET_ID = 'data-snippet-id';
@@ -0,0 +1,5 @@
1
+ export { default as MarkdownCopyClipboard } from './MarkdownCopyClipboard';
2
+ export { default as useInlineCopyClipboardShowdownExtension } from './inline-clipboard-extension';
3
+ export { default as useMultilineCopyClipboardShowdownExtension } from './multiline-clipboard-extension';
4
+ export { default as useAdmonitionShowdownExtension } from './admonition-extension';
5
+ export { default as useCodeShowdownExtension } from './code-extension';
@@ -0,0 +1,45 @@
1
+ import * as React from 'react';
2
+ import { QuickStartContext, QuickStartContextValues } from '@quickstarts/utils/quick-start-context';
3
+ import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID } from './const';
4
+ import { removeTemplateWhitespace } from './utils';
5
+ import { renderToStaticMarkup } from 'react-dom/server';
6
+ import CopyIcon from '@patternfly/react-icons/dist/js/icons/copy-icon';
7
+ import './showdown-extension.scss';
8
+
9
+ const useInlineCopyClipboardShowdownExtension = () => {
10
+ const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
11
+ return React.useMemo(
12
+ () => ({
13
+ type: 'lang',
14
+ regex: /```[\n]\s*((((?!```).)*?\n)+)\s*```{{copy}}/g,
15
+ replace: (
16
+ text: string,
17
+ group: string,
18
+ subGroup: string,
19
+ groupType: string,
20
+ groupId: string,
21
+ ): string => {
22
+ if (!group || !subGroup || !groupType || !groupId) {
23
+ return text;
24
+ }
25
+ return removeTemplateWhitespace(
26
+ `<span class="pf-c-clipboard-copy pf-m-inline">
27
+ <span class="pf-c-clipboard-copy__text" ${MARKDOWN_SNIPPET_ID}="${groupType}">${group}</span>
28
+ <span class="pf-c-clipboard-copy__actions">
29
+ <span class="pf-c-clipboard-copy__actions-item">
30
+ <button class="pf-c-button pf-m-plain" aria-label="${getResource(
31
+ 'Copy to clipboard',
32
+ )}" ${MARKDOWN_COPY_BUTTON_ID}="${groupType}">
33
+ ${renderToStaticMarkup(<CopyIcon />)}
34
+ </button>
35
+ </span>
36
+ </span>
37
+ </span>`,
38
+ );
39
+ },
40
+ }),
41
+ [getResource],
42
+ );
43
+ };
44
+
45
+ export default useInlineCopyClipboardShowdownExtension;
@@ -0,0 +1,50 @@
1
+ import * as React from 'react';
2
+ import { QuickStartContext, QuickStartContextValues } from '@quickstarts/utils/quick-start-context';
3
+ import { MARKDOWN_COPY_BUTTON_ID, MARKDOWN_SNIPPET_ID } from './const';
4
+ import { renderToStaticMarkup } from 'react-dom/server';
5
+ import CopyIcon from '@patternfly/react-icons/dist/js/icons/copy-icon';
6
+
7
+ import './showdown-extension.scss';
8
+
9
+ const useMultilineCopyClipboardShowdownExtension = () => {
10
+ const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
11
+ return React.useMemo(
12
+ () => ({
13
+ type: 'lang',
14
+ regex: /```[\n]((.*?\n)+)```{{copy}}/g,
15
+ replace: (
16
+ text: string,
17
+ group: string,
18
+ subgroup: string,
19
+ groupType: string,
20
+ groupId: string,
21
+ ): string => {
22
+ if (!group || !subgroup || !groupType || !groupId) {
23
+ return text;
24
+ }
25
+ return `<div class="pf-c-code-block">
26
+ <div class="pf-c-code-block__header">
27
+ <div class="pf-c-code-block__actions">
28
+ <div class="pf-c-code-block__actions-item">
29
+ <button class="pf-c-button pf-m-plain" type="button" aria-label="${getResource(
30
+ 'Copy to clipboard',
31
+ )}" ${MARKDOWN_COPY_BUTTON_ID}="${groupType}">
32
+ ${renderToStaticMarkup(<CopyIcon />)}
33
+ </button>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ <div class="pf-c-code-block__content">
38
+ <pre class="pf-c-code-block__pre pfext-code-block__pre">
39
+ <code class="pf-c-code-block__code"
40
+ ${MARKDOWN_SNIPPET_ID}="${groupType}">${group}</code>
41
+ </pre>
42
+ </div>
43
+ </div>`;
44
+ },
45
+ }),
46
+ [getResource],
47
+ );
48
+ };
49
+
50
+ export default useMultilineCopyClipboardShowdownExtension;
@@ -0,0 +1,52 @@
1
+ .pfext-markdown-view {
2
+ .pfext-code-block__pre {
3
+ /* override the styles applied by showdown while parsing <pre /> */
4
+ display: flex;
5
+ border: none;
6
+ border-radius: none;
7
+ background-color: transparent;
8
+ margin: 0;
9
+ padding: 0;
10
+ }
11
+
12
+ .pfext-markdown-execute-snippet {
13
+
14
+ &__button {
15
+ & > i.fa-check {
16
+ display: none;
17
+ }
18
+
19
+ & > i.fa-play {
20
+ display: inline;
21
+ }
22
+
23
+ &[data-executed] {
24
+ & > i.fa-check {
25
+ display: inline;
26
+ }
27
+
28
+ & > i.fa-play {
29
+ display: none;
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ .pfext-markdown-admonition {
36
+ &.pf-c-alert {
37
+ // add margins to match design
38
+ margin: var(--pf-global--spacer--md) 0;
39
+ .pf-c-alert__title {
40
+ // remove margins from markdown css
41
+ margin-top: 0;
42
+ margin-bottom: 0;
43
+ // lift PF style specificity to override markdown css
44
+ font-weight: var(--pf-c-alert__title--FontWeight);
45
+ font-family: inherit;
46
+ line-height: inherit;
47
+ color: var(--pf-c-alert__title--Color);
48
+ word-break: break-word;
49
+ }
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ export const removeTemplateWhitespace = (template: string): string => {
2
+ return template.replace(/>(?:\s|\n)+</g, '><');
3
+ };
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ import { Spotlight } from '../spotlight';
3
+
4
+ type MarkdownHighlightExtensionProps = {
5
+ docContext: HTMLDocument;
6
+ rootSelector: string;
7
+ };
8
+ const MarkdownHighlightExtension: React.FC<MarkdownHighlightExtensionProps> = ({
9
+ docContext,
10
+ rootSelector,
11
+ }) => {
12
+ const [selector, setSelector] = React.useState<string>(null);
13
+ React.useEffect(() => {
14
+ const elements = docContext.querySelectorAll(`${rootSelector} [data-highlight]`);
15
+ let timeoutId: NodeJS.Timeout;
16
+ function startHighlight(e) {
17
+ const highlightId = e.target.getAttribute('data-highlight');
18
+ if (!highlightId) {
19
+ return;
20
+ }
21
+ setSelector(null);
22
+ timeoutId = setTimeout(() => {
23
+ setSelector(`[data-quickstart-id="${highlightId}"]`);
24
+ }, 0);
25
+ }
26
+ elements && elements.forEach((elm) => elm.addEventListener('click', startHighlight));
27
+ return () => {
28
+ clearTimeout(timeoutId);
29
+ elements && elements.forEach((elm) => elm.removeEventListener('click', startHighlight));
30
+ };
31
+ }, [docContext, rootSelector]);
32
+ React.useEffect(() => {
33
+ const elements = docContext.querySelectorAll(`${rootSelector} [class^=data-highlight__]`);
34
+ let timeoutId: NodeJS.Timeout;
35
+ function startHighlight(e) {
36
+ e.preventDefault();
37
+ const classes = e.target.getAttribute('class').split(' ');
38
+ let highlightId;
39
+ for (let i = 0; i < classes.length; i++) {
40
+ if (classes[0].startsWith('data-highlight__')) {
41
+ highlightId = classes[0].split('__')[1];
42
+ break;
43
+ }
44
+ }
45
+ if (!highlightId) {
46
+ return;
47
+ }
48
+ setSelector(null);
49
+ timeoutId = setTimeout(() => {
50
+ setSelector(`[data-quickstart-id="${highlightId}"]`);
51
+ }, 0);
52
+ }
53
+ elements && elements.forEach((elm) => elm.addEventListener('click', startHighlight));
54
+ return () => {
55
+ clearTimeout(timeoutId);
56
+ elements && elements.forEach((elm) => elm.removeEventListener('click', startHighlight));
57
+ };
58
+ }, [docContext, rootSelector]);
59
+ if (!selector) {
60
+ return null;
61
+ }
62
+ return <Spotlight selector={selector} interactive />;
63
+ };
64
+ export default MarkdownHighlightExtension;
@@ -0,0 +1,9 @@
1
+ export const LINK_LABEL = '[\\d\\w\\s-()$!]+';
2
+ export const HIGHLIGHT_ACTIONS = ['highlight'];
3
+ export const SELECTOR_ID = `[\\w-]+`;
4
+
5
+ // [linkLabel]{{action id}}
6
+ export const HIGHLIGHT_REGEXP = new RegExp(
7
+ `\\[(${LINK_LABEL})]{{(${HIGHLIGHT_ACTIONS.join('|')}) (${SELECTOR_ID})}}`,
8
+ 'g',
9
+ );
@@ -0,0 +1 @@
1
+ export { default as MarkdownHighlightExtension } from './MarkdownHighlightExtension';
@@ -0,0 +1,3 @@
1
+ .pfext-modal {
2
+ position: absolute !important;
3
+ }
@@ -0,0 +1,19 @@
1
+ import './Modal.scss';
2
+ import * as React from 'react';
3
+ import { Modal as PfModal, ModalProps as PfModalProps } from '@patternfly/react-core';
4
+ import { css } from '@patternfly/react-styles';
5
+
6
+ type ModalProps = {
7
+ isFullScreen?: boolean;
8
+ ref?: React.LegacyRef<PfModal>;
9
+ } & PfModalProps;
10
+
11
+ const Modal: React.FC<ModalProps> = ({ isFullScreen = false, className, ...props }) => (
12
+ <PfModal
13
+ {...props}
14
+ className={css('pfext-modal', className)}
15
+ appendTo={() => (isFullScreen ? document.body : document.querySelector('#modal-container'))}
16
+ />
17
+ );
18
+
19
+ export default Modal;
@@ -0,0 +1 @@
1
+ export { default as Modal } from './Modal';
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import * as ReactDOM from 'react-dom';
3
+
4
+ type GetContainer = Element | null | undefined | (() => Element);
5
+
6
+ type PortalProps = {
7
+ container?: GetContainer;
8
+ };
9
+
10
+ const getContainer = (container: GetContainer): Element | null | undefined =>
11
+ typeof container === 'function' ? container() : container;
12
+
13
+ const Portal: React.FC<PortalProps> = ({ children, container }) => {
14
+ const [containerNode, setContainerNode] = React.useState<Element>();
15
+
16
+ React.useLayoutEffect(() => {
17
+ setContainerNode(getContainer(container) || document.body);
18
+ }, [container]);
19
+
20
+ return containerNode ? ReactDOM.createPortal(children, containerNode) : null;
21
+ };
22
+
23
+ export default Portal;
@@ -0,0 +1,90 @@
1
+ import * as React from 'react';
2
+ import Portal from './Portal';
3
+
4
+ const SimplePopper: React.FC = ({ children }) => {
5
+ const openProp = true;
6
+ const nodeRef = React.useRef<Element>();
7
+ const popperRef = React.useRef(null);
8
+ const [isOpen, setOpenState] = React.useState(openProp);
9
+
10
+ const setOpen = React.useCallback((newOpen: boolean) => {
11
+ setOpenState(newOpen);
12
+ }, []);
13
+
14
+ React.useEffect(() => {
15
+ setOpen(openProp);
16
+ }, [openProp, setOpen]);
17
+
18
+ const onKeyDown = React.useCallback(
19
+ (e: KeyboardEvent) => {
20
+ if (e.keyCode === 27) {
21
+ setOpen(false);
22
+ }
23
+ },
24
+ [setOpen],
25
+ );
26
+
27
+ const onClickOutside = React.useCallback(
28
+ (e: MouseEvent) => {
29
+ if (!nodeRef.current || (e.target instanceof Node && !nodeRef.current.contains(e.target))) {
30
+ setOpen(false);
31
+ }
32
+ },
33
+ [setOpen],
34
+ );
35
+
36
+ const destroy = React.useCallback(() => {
37
+ if (popperRef.current) {
38
+ popperRef.current.destroy();
39
+ document.removeEventListener('keydown', onKeyDown, true);
40
+ document.removeEventListener('mousedown', onClickOutside, true);
41
+ document.removeEventListener('touchstart', onClickOutside, true);
42
+ }
43
+ }, [onClickOutside, onKeyDown]);
44
+
45
+ const initialize = React.useCallback(() => {
46
+ if (!nodeRef.current || !isOpen) {
47
+ return;
48
+ }
49
+
50
+ destroy();
51
+ }, [isOpen, destroy]);
52
+
53
+ const nodeRefCallback = React.useCallback(
54
+ (node) => {
55
+ nodeRef.current = node;
56
+ initialize();
57
+ },
58
+ [initialize],
59
+ );
60
+
61
+ React.useEffect(() => {
62
+ initialize();
63
+ }, [initialize]);
64
+
65
+ React.useEffect(() => {
66
+ return () => {
67
+ destroy();
68
+ };
69
+ }, [destroy]);
70
+
71
+ React.useEffect(() => {
72
+ if (!isOpen) {
73
+ destroy();
74
+ }
75
+ }, [destroy, isOpen]);
76
+
77
+ return isOpen ? (
78
+ <Portal>
79
+ <div
80
+ ref={nodeRefCallback}
81
+ style={{ zIndex: 9999, position: 'absolute', top: 0, left: 0 }}
82
+ className="pfext-quick-start__base"
83
+ >
84
+ {children}
85
+ </div>
86
+ </Portal>
87
+ ) : null;
88
+ };
89
+
90
+ export default SimplePopper;
@@ -0,0 +1,2 @@
1
+ export { default as SimplePopper } from './SimplePopper';
2
+ export { default as Portal } from './Portal';
@@ -0,0 +1,58 @@
1
+ import './spotlight.scss';
2
+ import * as React from 'react';
3
+ import { Portal, SimplePopper } from '../popper';
4
+
5
+ type InteractiveSpotlightProps = {
6
+ element: Element;
7
+ };
8
+
9
+ const isInViewport = (elementToCheck: Element) => {
10
+ const rect = elementToCheck.getBoundingClientRect();
11
+ return (
12
+ rect.top >= 0 &&
13
+ rect.left >= 0 &&
14
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
15
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
16
+ );
17
+ };
18
+
19
+ const InteractiveSpotlight: React.FC<InteractiveSpotlightProps> = ({ element }) => {
20
+ const { top, bottom, left, right, height, width } = element.getBoundingClientRect();
21
+ const style: React.CSSProperties = {
22
+ height,
23
+ width,
24
+ top,
25
+ left,
26
+ bottom,
27
+ right,
28
+ };
29
+ const [clicked, setClicked] = React.useState(false);
30
+
31
+ React.useEffect(() => {
32
+ if (!clicked) {
33
+ if (!isInViewport(element)) {
34
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
35
+ }
36
+ const handleClick = () => setClicked(true);
37
+ document.addEventListener('click', handleClick);
38
+ return () => {
39
+ document.removeEventListener('click', handleClick);
40
+ };
41
+ }
42
+ return () => {};
43
+ }, [element, clicked]);
44
+
45
+ if (clicked) {
46
+ return null;
47
+ }
48
+
49
+ return (
50
+ <Portal>
51
+ <SimplePopper>
52
+ <div className="pfext-spotlight pfext-spotlight__element-highlight-animate" style={style} />
53
+ </SimplePopper>
54
+ </Portal>
55
+ );
56
+ };
57
+
58
+ export default InteractiveSpotlight;