@patternfly/quickstarts 6.3.0-prerelease.5 → 6.3.0-prerelease.7

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.
@@ -1,6 +1,6 @@
1
1
  declare const useAccordionShowdownExtension: () => {
2
2
  type: string;
3
3
  regex: RegExp;
4
- replace: (_text: string, accordionContent: string, _command: string, accordionHeading: string) => string;
4
+ replace: (_text: string, accordionContent: string, _command: string, _quotedHeading: string, accordionHeading: string) => string;
5
5
  };
6
6
  export default useAccordionShowdownExtension;
@@ -1,6 +1,6 @@
1
1
  declare const useAdmonitionShowdownExtension: () => {
2
2
  type: string;
3
3
  regex: RegExp;
4
- replace: (text: string, content: string, admonitionLabel: string, admonitionType: string, groupId: string) => string;
4
+ replace: (text: string, content: string, admonitionLabel: string, admonitionType: string) => string;
5
5
  };
6
6
  export default useAdmonitionShowdownExtension;
package/dist/index.es.js CHANGED
@@ -1153,6 +1153,155 @@ const useMultilineCopyClipboardShowdownExtension = () => {
1153
1153
  }), [getResource]);
1154
1154
  };
1155
1155
 
1156
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1157
+ const DOMPurify$2 = require('dompurify');
1158
+ var AdmonitionType;
1159
+ (function (AdmonitionType) {
1160
+ AdmonitionType["TIP"] = "TIP";
1161
+ AdmonitionType["NOTE"] = "NOTE";
1162
+ AdmonitionType["IMPORTANT"] = "IMPORTANT";
1163
+ AdmonitionType["WARNING"] = "WARNING";
1164
+ AdmonitionType["CAUTION"] = "CAUTION";
1165
+ })(AdmonitionType || (AdmonitionType = {}));
1166
+ const admonitionToAlertVariantMap = {
1167
+ [AdmonitionType.NOTE]: { variant: 'info' },
1168
+ [AdmonitionType.TIP]: { variant: 'custom', customIcon: jsx(LightbulbIcon, {}) },
1169
+ [AdmonitionType.IMPORTANT]: { variant: 'danger' },
1170
+ [AdmonitionType.CAUTION]: { variant: 'warning', customIcon: jsx(FireIcon, {}) },
1171
+ [AdmonitionType.WARNING]: { variant: 'warning' },
1172
+ };
1173
+ const useAdmonitionShowdownExtension = () =>
1174
+ // const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
1175
+ useMemo(() => ({
1176
+ type: 'lang',
1177
+ regex: /\[(.+)]{{(admonition) ([\w-]+)}}/g,
1178
+ replace: (text, content, admonitionLabel, admonitionType) => {
1179
+ if (!content || !admonitionLabel || !admonitionType) {
1180
+ return text;
1181
+ }
1182
+ if (admonitionLabel !== 'admonition') {
1183
+ return text;
1184
+ }
1185
+ admonitionType = admonitionType.toUpperCase();
1186
+ // Process markdown content directly using marked
1187
+ const processedContent = marked.parseInline(content);
1188
+ const sanitizedContent = DOMPurify$2.sanitize(processedContent);
1189
+ // Handle unknown admonition types by defaulting to NOTE
1190
+ const admonitionConfig = admonitionToAlertVariantMap[admonitionType] || admonitionToAlertVariantMap.NOTE;
1191
+ const { variant, customIcon } = admonitionConfig;
1192
+ const pfAlert = (jsx(Alert, Object.assign({ variant: variant }, (customIcon && { customIcon }), { isInline: true, title: admonitionType, className: "pfext-markdown-admonition" }, { children: jsx("div", { dangerouslySetInnerHTML: { __html: sanitizedContent } }) })));
1193
+ return removeTemplateWhitespace(renderToStaticMarkup(pfAlert));
1194
+ },
1195
+ }), []);
1196
+
1197
+ const useCodeShowdownExtension = () => useMemo(() => ({
1198
+ type: 'output',
1199
+ regex: /<pre><code>(.*?)\n?<\/code><\/pre>/g,
1200
+ replace: (text, content) => {
1201
+ if (!content) {
1202
+ return text;
1203
+ }
1204
+ const pfCodeBlock = jsx(CodeBlock, { children: content });
1205
+ return removeTemplateWhitespace(renderToStaticMarkup(pfCodeBlock));
1206
+ },
1207
+ }), []);
1208
+
1209
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1210
+ const DOMPurify$1 = require('dompurify');
1211
+ const useAccordionShowdownExtension = () => useMemo(() => ({
1212
+ type: 'lang',
1213
+ regex: /\[(.+)]{{(accordion) (&quot;(.*?)&quot;)}}/g,
1214
+ replace: (_text, accordionContent, _command, _quotedHeading, accordionHeading) => {
1215
+ const accordionId = String(accordionHeading).replace(/\s/g, '-');
1216
+ // Process accordion content with markdown
1217
+ const processedContent = marked.parseInline(accordionContent);
1218
+ const sanitizedContent = DOMPurify$1.sanitize(processedContent);
1219
+ return removeTemplateWhitespace(renderToStaticMarkup(jsx(Accordion, { children: jsxs(AccordionItem, { children: [jsx(AccordionToggle, Object.assign({ id: `${ACCORDION_MARKDOWN_BUTTON_ID}-${accordionId}` }, { children: accordionHeading })), jsx(AccordionContent, Object.assign({ id: `${ACCORDION_MARKDOWN_CONTENT_ID}-${accordionId}`, hidden: true }, { children: jsx("div", { dangerouslySetInnerHTML: { __html: sanitizedContent } }) }))] }) })));
1220
+ },
1221
+ }), []);
1222
+
1223
+ const AccordionShowdownHandler = ({ buttonElement, contentElement, }) => {
1224
+ const [expanded, setExpanded] = useState(false);
1225
+ const handleClick = () => {
1226
+ const newExpanded = !expanded;
1227
+ const expandedModifier = 'pf-m-expanded';
1228
+ // Find the accordion item element (parent of the button)
1229
+ const accordionItem = buttonElement.closest('.pf-v6-c-accordion__item');
1230
+ // Update button - both visual state and aria-expanded
1231
+ buttonElement.className = `pf-v6-c-accordion__toggle ${newExpanded ? expandedModifier : ''}`;
1232
+ buttonElement.setAttribute('aria-expanded', newExpanded.toString());
1233
+ // Update content - both visual state and hidden attribute
1234
+ contentElement.hidden = !newExpanded;
1235
+ contentElement.className = `pf-v6-c-accordion__expandable-content ${newExpanded ? expandedModifier : ''}`;
1236
+ // Update accordion item
1237
+ if (accordionItem) {
1238
+ accordionItem.className = `pf-v6-c-accordion__item ${newExpanded ? expandedModifier : ''}`;
1239
+ }
1240
+ setExpanded(newExpanded);
1241
+ };
1242
+ useEventListener(buttonElement, 'click', handleClick);
1243
+ return jsx(Fragment$1, {});
1244
+ };
1245
+ const AccordionRenderExtension = ({ docContext }) => {
1246
+ const buttonElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_BUTTON_ID}]`);
1247
+ const contentElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_CONTENT_ID}]`);
1248
+ return buttonElements.length > 0 ? (jsx(Fragment$1, { children: Array.from(buttonElements).map((elm) => {
1249
+ const content = Array.from(contentElements).find((elm2) => {
1250
+ const elmId = elm.id.split(ACCORDION_MARKDOWN_BUTTON_ID)[1];
1251
+ const elm2Id = elm2.id.split(ACCORDION_MARKDOWN_CONTENT_ID)[1];
1252
+ return elmId === elm2Id;
1253
+ });
1254
+ return (jsx(AccordionShowdownHandler, { buttonElement: elm, contentElement: content }, elm.id.split(ACCORDION_MARKDOWN_BUTTON_ID)[1]));
1255
+ }) })) : null;
1256
+ };
1257
+
1258
+ const FallbackImg = ({ src, alt, className, fallback }) => {
1259
+ const [isSrcValid, setIsSrcValid] = useState(true);
1260
+ if (src && isSrcValid) {
1261
+ return jsx("img", { className: className, src: src, alt: alt, onError: () => setIsSrcValid(false) });
1262
+ }
1263
+ return jsx(Fragment$1, { children: fallback });
1264
+ };
1265
+
1266
+ const DASH = '-';
1267
+
1268
+ const PopoverStatus = ({ hideHeader, children, isVisible = null, statusBody, title, onHide, onShow, }) => (jsx(Popover, Object.assign({ position: PopoverPosition.right, headerContent: hideHeader ? null : title, bodyContent: children, "aria-label": title, onHide: onHide, onShow: onShow, isVisible: isVisible }, { children: jsx(Button, Object.assign({ variant: "link", isInline: true }, { children: statusBody })) })));
1269
+
1270
+ const StatusIconAndText = ({ icon, title, spin, iconOnly, noTooltip, className, }) => {
1271
+ if (!title) {
1272
+ return jsx(Fragment$1, { children: DASH });
1273
+ }
1274
+ return (jsxs("span", Object.assign({ className: css('pfext-icon-and-text', className), title: iconOnly && !noTooltip ? title : undefined }, { children: [icon &&
1275
+ cloneElement(icon, {
1276
+ className: css(spin && 'fa-spin', icon.props.className, !iconOnly && 'pfext-icon-and-text__icon pfext-icon-flex-child'),
1277
+ }), !iconOnly && jsx(CamelCaseWrap, { value: title, dataTest: "status-text" })] })));
1278
+ };
1279
+
1280
+ const GenericStatus = (props) => {
1281
+ const { Icon, children, popoverTitle, title, noTooltip, iconOnly } = props, restProps = __rest(props, ["Icon", "children", "popoverTitle", "title", "noTooltip", "iconOnly"]);
1282
+ const renderIcon = iconOnly && !noTooltip ? jsx(Icon, { title: title }) : jsx(Icon, {});
1283
+ const statusBody = (jsx(StatusIconAndText, Object.assign({}, restProps, { noTooltip: noTooltip, title: title, iconOnly: iconOnly, icon: renderIcon })));
1284
+ return Children.toArray(children).length ? (jsx(PopoverStatus, Object.assign({ title: popoverTitle || title }, restProps, { statusBody: statusBody }, { children: children }))) : (statusBody);
1285
+ };
1286
+
1287
+ const GreenCheckCircleIcon = ({ className, title, size }) => (jsx(Icon, Object.assign({ size: size, status: "success" }, { children: jsx(CheckCircleIcon, { "data-test": "success-icon", className: className, title: title }) })));
1288
+
1289
+ const SuccessStatus = (props) => (jsx(GenericStatus, Object.assign({}, props, { Icon: GreenCheckCircleIcon, title: props.title || 'Healthy' })));
1290
+ SuccessStatus.displayName = 'SuccessStatus';
1291
+
1292
+ const Status = ({ status, title, iconOnly, noTooltip, className }) => {
1293
+ const statusProps = { title: title || status, iconOnly, noTooltip, className };
1294
+ switch (status) {
1295
+ case 'In Progress':
1296
+ return jsx(StatusIconAndText, Object.assign({}, statusProps, { icon: jsx(SyncAltIcon, {}) }));
1297
+ case 'Complete':
1298
+ return jsx(SuccessStatus, Object.assign({}, statusProps));
1299
+ default:
1300
+ return jsx(Fragment$1, { children: status || DASH });
1301
+ }
1302
+ };
1303
+ const StatusIcon = ({ status }) => jsx(Status, { status: status, iconOnly: true });
1304
+
1156
1305
  // eslint-disable-next-line @typescript-eslint/no-require-imports
1157
1306
  const DOMPurify = require('dompurify');
1158
1307
  const markdownConvert = (markdown, extensions) => __awaiter(void 0, void 0, void 0, function* () {
@@ -1164,7 +1313,7 @@ const markdownConvert = (markdown, extensions) => __awaiter(void 0, void 0, void
1164
1313
  node.setAttribute('rel', 'noopener noreferrer');
1165
1314
  return node;
1166
1315
  }
1167
- // add PF content classes
1316
+ // add PF content classes to standard elements (details blocks get handled separately)
1168
1317
  if (node.nodeType === 1) {
1169
1318
  const contentElements = [
1170
1319
  'ul',
@@ -1215,13 +1364,82 @@ const markdownConvert = (markdown, extensions) => __awaiter(void 0, void 0, void
1215
1364
  const reversedMarkdown = reverseString(markdown);
1216
1365
  const reverseMarkdownWithSubstitutedCodeFences = reversedMarkdown.replace(/{{```((.|\n)*?)```/g, '{{@@@$1@@@');
1217
1366
  const markdownWithSubstitutedCodeFences = reverseString(reverseMarkdownWithSubstitutedCodeFences);
1218
- const parsedMarkdown = yield marked.parse(markdownWithSubstitutedCodeFences);
1367
+ // Fix malformed HTML entities early in the process
1368
+ let preprocessedMarkdown = markdownWithSubstitutedCodeFences;
1369
+ preprocessedMarkdown = preprocessedMarkdown
1370
+ .replace(/&nbsp([^;])/g, '&nbsp;$1')
1371
+ .replace(/&amp;nbsp;/g, '&nbsp;');
1372
+ preprocessedMarkdown = preprocessedMarkdown.replace(/&nbsp(?![;])/g, '&nbsp;');
1373
+ // Process content in segments to ensure markdown parsing continues after HTML blocks
1374
+ const htmlBlockRegex = /(<(?:details|div|section|article)[^>]*>[\s\S]*?<\/(?:details|div|section|article)>)/g;
1375
+ let parsedMarkdown = '';
1376
+ // Check if there are any HTML blocks
1377
+ if (htmlBlockRegex.test(preprocessedMarkdown)) {
1378
+ // Reset regex for actual processing
1379
+ htmlBlockRegex.lastIndex = 0;
1380
+ let lastIndex = 0;
1381
+ let match;
1382
+ while ((match = htmlBlockRegex.exec(preprocessedMarkdown)) !== null) {
1383
+ // Process markdown before the HTML block
1384
+ const markdownBefore = preprocessedMarkdown.slice(lastIndex, match.index).trim();
1385
+ if (markdownBefore) {
1386
+ const parsed = yield marked.parse(markdownBefore);
1387
+ parsedMarkdown += parsed;
1388
+ }
1389
+ // Process the HTML block: parse markdown content inside while preserving HTML structure
1390
+ let htmlBlock = match[1];
1391
+ // Find and process markdown content inside HTML tags
1392
+ const contentRegex = />(\s*[\s\S]*?)\s*</g;
1393
+ const contentMatches = [];
1394
+ let contentMatch;
1395
+ while ((contentMatch = contentRegex.exec(htmlBlock)) !== null) {
1396
+ const content = contentMatch[1];
1397
+ // Only process content that has markdown formatting but no extension syntax
1398
+ if (content.trim() &&
1399
+ !content.includes('{{') &&
1400
+ (content.includes('**') || content.includes('- ') || content.includes('\n'))) {
1401
+ // This looks like markdown content without extensions - parse it as block content
1402
+ const parsedContent = yield marked.parse(content.trim());
1403
+ // Remove wrapping <p> tags if they exist since we're inside HTML already
1404
+ const cleanedContent = parsedContent.replace(/^<p[^>]*>([\s\S]*)<\/p>[\s]*$/g, '$1');
1405
+ contentMatches.push({
1406
+ original: contentMatch[0],
1407
+ replacement: `>${cleanedContent}<`,
1408
+ });
1409
+ }
1410
+ }
1411
+ // Apply the content replacements
1412
+ contentMatches.forEach(({ original, replacement }) => {
1413
+ htmlBlock = htmlBlock.replace(original, replacement);
1414
+ });
1415
+ // Apply extensions (like admonitions) to the processed HTML block
1416
+ if (extensions) {
1417
+ extensions.forEach(({ regex, replace }) => {
1418
+ if (regex) {
1419
+ htmlBlock = htmlBlock.replace(regex, replace);
1420
+ }
1421
+ });
1422
+ }
1423
+ parsedMarkdown += htmlBlock;
1424
+ lastIndex = htmlBlockRegex.lastIndex;
1425
+ }
1426
+ // Process any remaining markdown after the last HTML block
1427
+ const markdownAfter = preprocessedMarkdown.slice(lastIndex).trim();
1428
+ if (markdownAfter) {
1429
+ const parsed = yield marked.parse(markdownAfter);
1430
+ parsedMarkdown += parsed;
1431
+ }
1432
+ }
1433
+ else {
1434
+ // No HTML blocks found, process normally
1435
+ parsedMarkdown = yield marked.parse(preprocessedMarkdown);
1436
+ }
1219
1437
  // Swap the temporary tokens back to code fences before we run the extensions
1220
1438
  let md = parsedMarkdown.replace(/@@@/g, '```');
1221
1439
  if (extensions) {
1222
1440
  // Convert code spans back to md format before we run the custom extension regexes
1223
1441
  md = md.replace(/<code>(.*)<\/code>/g, '`$1`');
1224
- extensions.forEach(({ regex, replace }) => {
1442
+ extensions.forEach(({ regex, replace }, _index) => {
1225
1443
  if (regex) {
1226
1444
  md = md.replace(regex, replace);
1227
1445
  }
@@ -1286,7 +1504,7 @@ const RenderExtension = ({ renderExtension, selector, markup, docContext, }) =>
1286
1504
  };
1287
1505
  const InlineMarkdownView = ({ markup, isEmpty, renderExtension, className, }) => {
1288
1506
  const id = useMemo(() => uniqueId('markdown'), []);
1289
- return (jsxs("div", Object.assign({ className: css({ 'is-empty': isEmpty }, className), id: id }, { children: [jsx("div", { dangerouslySetInnerHTML: { __html: markup } }), renderExtension && (jsx(RenderExtension, { renderExtension: renderExtension, selector: `#${id}`, markup: markup }))] })));
1507
+ return (jsxs("div", Object.assign({ className: css({ 'is-empty': isEmpty }, className), id: id }, { children: [jsx("div", { style: { marginBlockEnd: 'var(--pf-t-global--spacer--md)' }, dangerouslySetInnerHTML: { __html: markup } }), renderExtension && (jsx(RenderExtension, { renderExtension: renderExtension, selector: `#${id}`, markup: markup }))] })));
1290
1508
  };
1291
1509
  const IFrameMarkdownView = ({ exactHeight, markup, isEmpty, renderExtension, className, }) => {
1292
1510
  const [frame, setFrame] = useState();
@@ -1345,7 +1563,7 @@ const IFrameMarkdownView = ({ exactHeight, markup, isEmpty, renderExtension, cla
1345
1563
  }
1346
1564
  </style>
1347
1565
  <body class="pf-m-redhat-font"><div style="overflow-y: auto;">${markup}</div></body>`;
1348
- return (jsxs(Fragment$1, { children: [jsx("iframe", { sandbox: "allow-popups allow-popups-to-escape-sandbox allow-same-origin", srcDoc: contents, style: { border: '0px', display: 'block', width: '100%', height: '0' }, ref: (r) => {
1566
+ return (jsxs(Fragment$1, { children: [jsx("iframe", { title: "Markdown content preview", sandbox: "allow-popups allow-popups-to-escape-sandbox allow-same-origin", srcDoc: contents, style: { border: '0px', display: 'block', width: '100%', height: '0' }, ref: (r) => {
1349
1567
  setFrame(r);
1350
1568
  }, onLoad: () => onLoad(), className: className }), loaded && frame && renderExtension && (jsx(RenderExtension, { markup: markup, selector: '', renderExtension: renderExtension, docContext: frame.contentDocument }))] }));
1351
1569
  };
@@ -1393,131 +1611,6 @@ const QuickStartMarkdownView = ({ content, exactHeight, className, }) => {
1393
1611
  markdown.renderExtension(docContext, rootSelector)] })), className: className }));
1394
1612
  };
1395
1613
 
1396
- var AdmonitionType;
1397
- (function (AdmonitionType) {
1398
- AdmonitionType["TIP"] = "TIP";
1399
- AdmonitionType["NOTE"] = "NOTE";
1400
- AdmonitionType["IMPORTANT"] = "IMPORTANT";
1401
- AdmonitionType["WARNING"] = "WARNING";
1402
- AdmonitionType["CAUTION"] = "CAUTION";
1403
- })(AdmonitionType || (AdmonitionType = {}));
1404
- const admonitionToAlertVariantMap = {
1405
- [AdmonitionType.NOTE]: { variant: 'info' },
1406
- [AdmonitionType.TIP]: { variant: 'custom', customIcon: jsx(LightbulbIcon, {}) },
1407
- [AdmonitionType.IMPORTANT]: { variant: 'danger' },
1408
- [AdmonitionType.CAUTION]: { variant: 'warning', customIcon: jsx(FireIcon, {}) },
1409
- [AdmonitionType.WARNING]: { variant: 'warning' },
1410
- };
1411
- const useAdmonitionShowdownExtension = () =>
1412
- // const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
1413
- useMemo(() => ({
1414
- type: 'lang',
1415
- regex: /\[(.+)]{{(admonition) ([\w-]+)}}/g,
1416
- replace: (text, content, admonitionLabel, admonitionType, groupId) => {
1417
- if (!content || !admonitionLabel || !admonitionType || !groupId) {
1418
- return text;
1419
- }
1420
- admonitionType = admonitionType.toUpperCase();
1421
- const { variant, customIcon } = admonitionToAlertVariantMap[admonitionType];
1422
- const mdContent = jsx(QuickStartMarkdownView, { content: content });
1423
- const pfAlert = (jsx(Alert, Object.assign({ variant: variant }, (customIcon && { customIcon }), { isInline: true, title: admonitionType, className: "pfext-markdown-admonition" }, { children: mdContent })));
1424
- return removeTemplateWhitespace(renderToStaticMarkup(pfAlert));
1425
- },
1426
- }), []);
1427
-
1428
- const useCodeShowdownExtension = () => useMemo(() => ({
1429
- type: 'output',
1430
- regex: /<pre><code>(.*?)\n?<\/code><\/pre>/g,
1431
- replace: (text, content) => {
1432
- if (!content) {
1433
- return text;
1434
- }
1435
- const pfCodeBlock = jsx(CodeBlock, { children: content });
1436
- return removeTemplateWhitespace(renderToStaticMarkup(pfCodeBlock));
1437
- },
1438
- }), []);
1439
-
1440
- const useAccordionShowdownExtension = () => useMemo(() => ({
1441
- type: 'lang',
1442
- regex: /\[(.+)]{{(accordion) ("(.*?)")}}/g,
1443
- replace: (_text, accordionContent, _command, accordionHeading) => {
1444
- const accordionId = String(accordionHeading).replace(/\s/g, '-');
1445
- return removeTemplateWhitespace(renderToStaticMarkup(jsx(Fragment$1, { children: jsx(Accordion, Object.assign({ asDefinitionList: true }, { children: jsxs(AccordionItem, Object.assign({ isExpanded: false }, { children: [jsx(AccordionToggle, Object.assign({ id: `${ACCORDION_MARKDOWN_BUTTON_ID}-${accordionId}` }, { children: accordionHeading })), jsx(AccordionContent, Object.assign({ id: `${ACCORDION_MARKDOWN_CONTENT_ID}-${accordionId}` }, { children: accordionContent }))] })) })) })));
1446
- },
1447
- }), []);
1448
-
1449
- const AccordionShowdownHandler = ({ buttonElement, contentElement, }) => {
1450
- const [expanded, setExpanded] = useState(false);
1451
- const handleClick = () => {
1452
- const expandedModifier = 'pf-m-expanded';
1453
- buttonElement.className = `pf-v6-c-accordion__toggle ${!expanded ? expandedModifier : ''}`;
1454
- contentElement.hidden = expanded;
1455
- contentElement.className = `pf-v6-c-accordion__expanded-content ${!expanded ? expandedModifier : ''}`;
1456
- setExpanded(!expanded);
1457
- };
1458
- useEventListener(buttonElement, 'click', handleClick);
1459
- return jsx(Fragment$1, {});
1460
- };
1461
- const AccordionRenderExtension = ({ docContext }) => {
1462
- const buttonElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_BUTTON_ID}]`);
1463
- const contentElements = docContext.querySelectorAll(`[id ^= ${ACCORDION_MARKDOWN_CONTENT_ID}]`);
1464
- return buttonElements.length > 0 ? (jsx(Fragment$1, { children: Array.from(buttonElements).map((elm) => {
1465
- const content = Array.from(contentElements).find((elm2) => {
1466
- const elmId = elm.id.split(ACCORDION_MARKDOWN_BUTTON_ID)[1];
1467
- const elm2Id = elm2.id.split(ACCORDION_MARKDOWN_CONTENT_ID)[1];
1468
- return elmId === elm2Id;
1469
- });
1470
- return (jsx(AccordionShowdownHandler, { buttonElement: elm, contentElement: content }, elm.id.split(ACCORDION_MARKDOWN_BUTTON_ID)[1]));
1471
- }) })) : null;
1472
- };
1473
-
1474
- const FallbackImg = ({ src, alt, className, fallback }) => {
1475
- const [isSrcValid, setIsSrcValid] = useState(true);
1476
- if (src && isSrcValid) {
1477
- return jsx("img", { className: className, src: src, alt: alt, onError: () => setIsSrcValid(false) });
1478
- }
1479
- return jsx(Fragment$1, { children: fallback });
1480
- };
1481
-
1482
- const DASH = '-';
1483
-
1484
- const PopoverStatus = ({ hideHeader, children, isVisible = null, statusBody, title, onHide, onShow, }) => (jsx(Popover, Object.assign({ position: PopoverPosition.right, headerContent: hideHeader ? null : title, bodyContent: children, "aria-label": title, onHide: onHide, onShow: onShow, isVisible: isVisible }, { children: jsx(Button, Object.assign({ variant: "link", isInline: true }, { children: statusBody })) })));
1485
-
1486
- const StatusIconAndText = ({ icon, title, spin, iconOnly, noTooltip, className, }) => {
1487
- if (!title) {
1488
- return jsx(Fragment$1, { children: DASH });
1489
- }
1490
- return (jsxs("span", Object.assign({ className: css('pfext-icon-and-text', className), title: iconOnly && !noTooltip ? title : undefined }, { children: [icon &&
1491
- cloneElement(icon, {
1492
- className: css(spin && 'fa-spin', icon.props.className, !iconOnly && 'pfext-icon-and-text__icon pfext-icon-flex-child'),
1493
- }), !iconOnly && jsx(CamelCaseWrap, { value: title, dataTest: "status-text" })] })));
1494
- };
1495
-
1496
- const GenericStatus = (props) => {
1497
- const { Icon, children, popoverTitle, title, noTooltip, iconOnly } = props, restProps = __rest(props, ["Icon", "children", "popoverTitle", "title", "noTooltip", "iconOnly"]);
1498
- const renderIcon = iconOnly && !noTooltip ? jsx(Icon, { title: title }) : jsx(Icon, {});
1499
- const statusBody = (jsx(StatusIconAndText, Object.assign({}, restProps, { noTooltip: noTooltip, title: title, iconOnly: iconOnly, icon: renderIcon })));
1500
- return Children.toArray(children).length ? (jsx(PopoverStatus, Object.assign({ title: popoverTitle || title }, restProps, { statusBody: statusBody }, { children: children }))) : (statusBody);
1501
- };
1502
-
1503
- const GreenCheckCircleIcon = ({ className, title, size }) => (jsx(Icon, Object.assign({ size: size, status: "success" }, { children: jsx(CheckCircleIcon, { "data-test": "success-icon", className: className, title: title }) })));
1504
-
1505
- const SuccessStatus = (props) => (jsx(GenericStatus, Object.assign({}, props, { Icon: GreenCheckCircleIcon, title: props.title || 'Healthy' })));
1506
- SuccessStatus.displayName = 'SuccessStatus';
1507
-
1508
- const Status = ({ status, title, iconOnly, noTooltip, className }) => {
1509
- const statusProps = { title: title || status, iconOnly, noTooltip, className };
1510
- switch (status) {
1511
- case 'In Progress':
1512
- return jsx(StatusIconAndText, Object.assign({}, statusProps, { icon: jsx(SyncAltIcon, {}) }));
1513
- case 'Complete':
1514
- return jsx(SuccessStatus, Object.assign({}, statusProps));
1515
- default:
1516
- return jsx(Fragment$1, { children: status || DASH });
1517
- }
1518
- };
1519
- const StatusIcon = ({ status }) => jsx(Status, { status: status, iconOnly: true });
1520
-
1521
1614
  const QuickStartTileDescription = ({ description, prerequisites, }) => {
1522
1615
  const { getResource } = useContext(QuickStartContext);
1523
1616
  const prereqs = prerequisites === null || prerequisites === void 0 ? void 0 : prerequisites.filter((p) => p);
@@ -1620,7 +1713,7 @@ const QuickStartCatalogFilterSelect = (_a) => {
1620
1713
  };
1621
1714
  const QuickStartCatalogFilterCount = ({ quickStartsCount }) => {
1622
1715
  const { getResource } = useContext(QuickStartContext);
1623
- return (jsx(ToolbarItem, Object.assign({ align: { default: 'alignEnd' } }, { children: getResource('{{count, number}} item', quickStartsCount).replace('{{count, number}}', quickStartsCount) })));
1716
+ return (jsx(ToolbarItem, Object.assign({ align: { default: 'alignEnd' } }, { children: getResource('{{count, number}} item', quickStartsCount) })));
1624
1717
  };
1625
1718
  const QuickStartCatalogFilterSearchWrapper = ({ onSearchInputChange = () => { } }) => {
1626
1719
  const { useQueryParams, filter, setFilter } = useContext(QuickStartContext);
@@ -1834,7 +1927,7 @@ const QuickStartIntroduction = ({ tasks, introduction, allTaskStatuses, prerequi
1834
1927
  const prereqs = prerequisites === null || prerequisites === void 0 ? void 0 : prerequisites.filter((p) => p);
1835
1928
  const [isPrereqsExpanded, setIsPrereqsExpanded] = useState(false);
1836
1929
  const prereqList = (prereqs === null || prereqs === void 0 ? void 0 : prereqs.length) > 0 && (jsx(ExpandableSection, Object.assign({ toggleText: getResource('View Prerequisites ({{totalPrereqs}})').replace('{{totalPrereqs}}', prereqs.length), onToggle: () => setIsPrereqsExpanded(!isPrereqsExpanded) }, { children: jsx(List, { children: prereqs.map((pr) => (jsx(ListItem, { children: jsx(QuickStartMarkdownView, { content: pr }) }, pr))) }) })));
1837
- return (jsxs(Stack, Object.assign({ hasGutter: true }, { children: [jsx(QuickStartMarkdownView, { content: introduction }), prereqList, jsxs("p", { children: [getResource('In this quick start, you will complete {{count, number}} task', tasks === null || tasks === void 0 ? void 0 : tasks.length).replace('{{count, number}}', (tasks === null || tasks === void 0 ? void 0 : tasks.length) || 0), ":"] }), jsx(QuickStartTaskHeaderList, { tasks: tasks, allTaskStatuses: allTaskStatuses, onTaskSelect: onTaskSelect })] })));
1930
+ return (jsxs(Stack, Object.assign({ hasGutter: true }, { children: [jsx(QuickStartMarkdownView, { content: introduction }), prereqList, jsxs("p", { children: [getResource('In this quick start, you will complete {{count, number}} task', (tasks === null || tasks === void 0 ? void 0 : tasks.length) || 0).replace('{{count, number}}', (tasks === null || tasks === void 0 ? void 0 : tasks.length) || 0), ":"] }), jsx(QuickStartTaskHeaderList, { tasks: tasks, allTaskStatuses: allTaskStatuses, onTaskSelect: onTaskSelect })] })));
1838
1931
  };
1839
1932
 
1840
1933
  const getAlertVariant = (status) => {
@@ -2007,7 +2100,7 @@ const QuickStartPanelContent = (_a) => {
2007
2100
  const QuickStartDrawerContent = (_a) => {
2008
2101
  var { quickStarts = [], appendTo, fullWidth, handleDrawerClose } = _a, props = __rest(_a, ["quickStarts", "appendTo", "fullWidth", "handleDrawerClose"]);
2009
2102
  const { activeQuickStartID, allQuickStarts = [], activeQuickStartState, } = useContext(QuickStartContext);
2010
- const combinedQuickStarts = allQuickStarts.concat(quickStarts);
2103
+ const combinedQuickStarts = [...allQuickStarts, ...quickStarts].filter((qs, idx, arr) => arr.findIndex((q) => q.metadata.name === qs.metadata.name) === idx);
2011
2104
  const handleClose = () => {
2012
2105
  handleDrawerClose && handleDrawerClose(activeQuickStartState === null || activeQuickStartState === void 0 ? void 0 : activeQuickStartState.status);
2013
2106
  };