UNPKG

@navinc/base-react-components

Version:
282 lines (257 loc) 11 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Article = exports.transformHTML = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const styled_components_1 = __importDefault(require("styled-components")); const htmr_1 = __importDefault(require("htmr")); const author_card_js_1 = require("./author-card.js"); const block_quote_js_1 = require("./block-quote.js"); const copy_js_1 = require("./copy.js"); const header_js_1 = require("./header.js"); const icon_js_1 = require("./icon.js"); const link_js_1 = require("./link.js"); const ArticleContent = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ArticleContent", componentId: "brc-sc-s1mp15" }) ` li { font-size: 16px; } p, span, ul, ol { padding-bottom: 16px; } ul, ol { padding-left: 40px; } ol { list-style-type: decimal; } ul { list-style-type: disc; } .wp-block-image, .callout-img { text-align: center; img { max-width: 100%; } } .title { font-weight: bold; } /* Creates an alert box that appears like a yellow banner, selecting only those that are not children of the same (in case of nested alerts) */ :not(.alert-box-warning) > .alert-box-warning { background-color: ${({ theme }) => theme.navSecondary}; position: relative; padding: 16px; border-radius: 12px; box-shadow: 0 10px 11px -8px rgb(0 0 0 / 12%); p { margin-left: 40px; } ::before { content: ''; width: 100%; height: 8px; position: absolute; left: 0; top: 0; background: ${({ theme }) => theme.navSecondary400}; border-radius: 14px 14px 0 0; } .icon-container { position: relative; height: 0; /* Renders the alert icon, parsing out # into its code so the SVG code does not break */ ::before { position: absolute; top: 0; left: 0; /* stylelint-disable string-no-newline -- should remain on one line after interpolation */ content: url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" fill="${({ theme }) => theme.navSecondary400.replace('#', '%23')}" viewBox="0 0 24 24" width="24" height="24"><path d="M12,8 C12.552,8 13,8.447 13,9 L13,13 C13,13.553 12.552,14 12,14 C11.448,14 11,13.553 11,13 L11,9 C11,8.447 11.448,8 12,8 Z M12,17 C11.4477153,17 11,16.5522847 11,16 C11,15.4477153 11.4477153,15 12,15 C12.5522847,15 13,15.4477153 13,16 C13,16.5522847 12.5522847,17 12,17 Z M12,22 C6.4771525,22 2,17.5228475 2,12 C2,6.4771525 6.4771525,2 12,2 C17.5228475,2 22,6.4771525 22,12 C22,17.5228475 17.5228475,22 12,22 Z M12,20 C16.418278,20 20,16.418278 20,12 C20,7.581722 16.418278,4 12,4 C7.581722,4 4,7.581722 4,12 C4,16.418278 7.581722,20 12,20 Z"></path></svg>'); /* stylelint-enable string-no-newline */ } } } /* Non-urgent callout cards in the middle of a paragraph */ .wp-block-nav-card, .nav-blocks-card-2 { padding: 16px; border-radius: 4px; box-shadow: 0 3px 23px rgb(0 0 0 / 10%); margin-bottom: 16px; } /* Table */ table { border-collapse: separate; border-spacing: 0; td, th { padding: 16px; border-right: 1px solid ${({ theme }) => theme.navNeutral300}; border-bottom: 1px solid ${({ theme }) => theme.navNeutral300}; vertical-align: top; } tr { td:first-child, th:first-child { border-left: 1px solid ${({ theme }) => theme.navNeutral300}; } } tr:first-child { td, th { border-top: 1px solid ${({ theme }) => theme.navNeutral300}; } td:first-child, th:first-child { border-top-left-radius: 20px; } td:last-child, th:last-child { border-top-right-radius: 20px; } } tr:last-child { td:first-child { border-bottom-left-radius: 20px; } td:last-child { border-bottom-right-radius: 20px; } } /* stylelint-disable no-descending-specificity -- nested rules would need to be moved around and probably duplicated */ tbody { tr:nth-child(even) { td, th { background-color: ${({ theme }) => theme.navNeutralLight}; } } tr:nth-child(odd) { td, th { background-color: ${({ theme }) => theme.navNeutral100}; } } } /* stylelint-enable no-descending-specificity */ } `; const HeaderContentWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-HeaderContentWrapper", componentId: "brc-sc-1092uwb" }) ` text-align: left; display: grid; grid-gap: 8px; padding-bottom: 24px; `; const HeaderWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-HeaderWrapper", componentId: "brc-sc-1kdj5b0" }) ` display: flex; justify-content: space-between; `; const SectionWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-SectionWrapper", componentId: "brc-sc-5xxjng" }) ` display: flex; flex-direction: column; padding: 18px; scroll-margin-top: 200px; `; const IconWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-IconWrapper", componentId: "brc-sc-ne8i5y" }) ` text-align: right; padding-top: 16px; `; const CloseButton = styled_components_1.default.div.withConfig({ displayName: "brc-sc-CloseButton", componentId: "brc-sc-52bbjm" }) ` display: flex; justify-content: flex-end; padding-top: 16px; & > ${icon_js_1.Icon} { fill: ${({ theme }) => theme.navNeutralDark}; margin-left: 8px; } &:hover { cursor: pointer; } `; const transform = { b: (node, props, children) => { var _a; return ((0, jsx_runtime_1.jsx)(copy_js_1.Copy, Object.assign({ bold: true }, props, { children: (_a = node === null || node === void 0 ? void 0 : node.children) !== null && _a !== void 0 ? _a : children }))); }, p: copy_js_1.Copy, span: copy_js_1.Copy, a: link_js_1.Link, h2: (node, props, children) => { var _a; return ((0, jsx_runtime_1.jsx)(header_js_1.Header, Object.assign({ size: "md" }, props, { children: (_a = node === null || node === void 0 ? void 0 : node.children) !== null && _a !== void 0 ? _a : children }))); }, h3: (node, props, children) => { var _a; return ((0, jsx_runtime_1.jsx)(header_js_1.Header, Object.assign({ size: "sm" }, props, { children: (_a = node === null || node === void 0 ? void 0 : node.children) !== null && _a !== void 0 ? _a : children }))); }, h4: (node, props, children) => { var _a; return ((0, jsx_runtime_1.jsx)(header_js_1.Header, Object.assign({ size: "xs" }, props, { children: (_a = node === null || node === void 0 ? void 0 : node.children) !== null && _a !== void 0 ? _a : children }))); }, blockquote: (node, props, children) => { var _a; return ((0, jsx_runtime_1.jsx)(block_quote_js_1.BlockQuote, Object.assign({}, props, { children: (_a = node === null || node === void 0 ? void 0 : node.children) !== null && _a !== void 0 ? _a : children }))); }, }; const transformHTML = (content = '') => { content = content.replace(/\r\n\r\n/g, '<br /><br />'); return (0, htmr_1.default)(content, { transform }); }; exports.transformHTML = transformHTML; const Article = ({ author, dateGmt, content, modifiedGmt, excerpt, title, shouldStartOpen }) => { const article = (0, react_1.useRef)(null); const [isOpen, setIsOpen] = (0, react_1.useState)(shouldStartOpen); const [articleHeight, setArticleHeight] = (0, react_1.useState)(0); const [hasFirstLoadFinished, setHasFirstLoadFinished] = (0, react_1.useState)(false); const hashId = title === null || title === void 0 ? void 0 : title.split(' ').join('-'); const hasBeenUpdated = !!modifiedGmt; const dateString = hasBeenUpdated ? `Updated ${new Date(modifiedGmt).toLocaleDateString()}` : new Date(dateGmt).toLocaleDateString(); const { name: authorName, bio, image, jobTitle } = author; (0, react_1.useEffect)(() => { if (shouldStartOpen && !isOpen) { setIsOpen(true); } }, [shouldStartOpen, isOpen]); // Calculating the offsetTop of the element should refresh each time it is toggled open/shut (0, react_1.useEffect)(() => { var _a, _b; if (article.current) { setArticleHeight((_b = (_a = article.current) === null || _a === void 0 ? void 0 : _a.offsetTop) !== null && _b !== void 0 ? _b : 0); } }, [article, isOpen]); /* When the article is closed, we should scroll to its top, and should only depend on when isOpen changes. */ (0, react_1.useLayoutEffect)(() => { if (!isOpen && hasFirstLoadFinished && articleHeight > 0) { window.scrollTo({ top: articleHeight }); } }, [isOpen, hasFirstLoadFinished, articleHeight]); // Set when the article has loaded so we prevent automatic scroll to the top (0, react_1.useEffect)(() => { if (!hasFirstLoadFinished) { setHasFirstLoadFinished(true); } }, [hasFirstLoadFinished]); if (!hasFirstLoadFinished) { return null; } return ((0, jsx_runtime_1.jsxs)(SectionWrapper, { id: hashId, ref: article, children: [(0, jsx_runtime_1.jsxs)(HeaderWrapper, { "data-testid": `article:header:${title}`, onClick: () => setIsOpen((isOpen) => !isOpen), children: [(0, jsx_runtime_1.jsxs)(HeaderContentWrapper, { children: [(0, jsx_runtime_1.jsx)(header_js_1.Header, { size: "xs", children: title }), (0, jsx_runtime_1.jsx)(copy_js_1.Copy, { light: true, size: "sm", boldType: "semiBold", children: `${dateString} | by ${authorName}` }), !isOpen && (0, jsx_runtime_1.jsx)(ArticleContent, { children: (0, exports.transformHTML)(excerpt) })] }), (0, jsx_runtime_1.jsx)(IconWrapper, { children: (0, jsx_runtime_1.jsx)(icon_js_1.Icon, { name: `actions/carrot-${isOpen ? 'up' : 'down'}` }) })] }), isOpen && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ArticleContent, { "data-testid": `article:content:${title}`, children: (0, exports.transformHTML)(content) }), (0, jsx_runtime_1.jsx)(author_card_js_1.AuthorCard, { description: bio, img: image, imgAlt: authorName, name: authorName, title: jobTitle }), (0, jsx_runtime_1.jsxs)(CloseButton, { "data-testid": `close-article:${title}`, onClick: () => { setIsOpen(false); }, children: [(0, jsx_runtime_1.jsx)(copy_js_1.Copy, { light: true, children: "Close" }), (0, jsx_runtime_1.jsx)(icon_js_1.Icon, { name: "actions/carrot-up" })] })] }))] })); }; exports.Article = Article; //# sourceMappingURL=article.js.map