@navinc/base-react-components
Version:
Nav's Pattern Library
306 lines (290 loc) • 13.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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 = __importStar(require("styled-components"));
const htmr_1 = __importDefault(require("htmr"));
const author_card_js_1 = __importDefault(require("./author-card.js"));
const block_quote_js_1 = __importDefault(require("./block-quote.js"));
const copy_js_1 = __importDefault(require("./copy.js"));
const header_js_1 = __importDefault(require("./header.js"));
const icon_js_1 = __importDefault(require("./icon.js"));
const link_js_1 = __importDefault(require("./link.js"));
const prop_types_1 = __importDefault(require("prop-types"));
const is_rebrand_js_1 = __importDefault(require("./is-rebrand.js"));
const ArticleContent = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ArticleContent", componentId: "brc-sc-wfc140" }) `
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 }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navSecondary200 : theme.flounderYellow100)};
position: relative;
padding: 16px;
border-radius: 12px;
box-shadow: 0 10px 11px -8px rgba(0, 0, 0, 0.12);
p {
margin-left: 40px;
}
.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;
content: ${({ theme }) => `url('data:image/svg+xml; utf8, <svg xmlns="http://www.w3.org/2000/svg" fill="${String((0, is_rebrand_js_1.default)(theme) ? theme.navSecondary400 : theme.flounderYellow200).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>')`};
}
}
::before {
content: '';
width: 100%;
height: 8px;
position: absolute;
left: 0;
top: 0;
background: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navSeconary400 : theme.flounderYellow200)};
border-radius: 14px 14px 0 0;
}
}
/* 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 rgba(0, 0, 0, 0.1);
margin-bottom: 16px;
}
/* Table */
table {
border-collapse: separate;
border-spacing: 0;
td,
th {
padding: 16px;
border-right: 1px solid ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.scuttleGray300)};
border-bottom: 1px solid ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.scuttleGray300)};
vertical-align: top;
}
tr {
td:first-child,
th:first-child {
border-left: 1px solid ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.scuttleGray300)};
}
}
tr:first-child {
td:first-child,
th:first-child {
border-top-left-radius: 20px;
}
td:last-child,
th:last-child {
border-top-right-radius: 20px;
}
td,
th {
border-top: 1px solid ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.scuttleGray300)};
}
}
tr:last-child {
td:first-child {
border-bottom-left-radius: 20px;
}
td:last-child {
border-bottom-right-radius: 20px;
}
}
tbody {
tr:nth-child(even) {
td,
th {
background-color: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navSecondary100 : theme.bubbleBlue100)};
}
}
tr:nth-child(odd) {
td,
th {
background-color: ${({ theme }) => (0, is_rebrand_js_1.default)(theme) && theme.navSecondary};
}
}
}
}
`;
const HeaderContentWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-HeaderContentWrapper", componentId: "brc-sc-1wrbiy3" }) `
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-1yuzpj4" }) `
display: flex;
justify-content: space-between;
`;
const SectionWrapper = styled_components_1.default.div.withConfig({ displayName: "brc-sc-SectionWrapper", componentId: "brc-sc-4tudhi" }) `
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-1mcib35" }) `
text-align: right;
padding-top: 16px;
`;
const CloseButton = styled_components_1.default.div.withConfig({ displayName: "brc-sc-CloseButton", componentId: "brc-sc-1piyeya" }) `
display: flex;
justify-content: flex-end;
padding-top: 16px;
& > ${icon_js_1.default} {
fill: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutralDark : theme.neutral400)};
margin-left: 8px;
}
&:hover {
cursor: pointer;
}
`;
const transform = {
b: (node, props, children) => {
var _a;
return ((0, jsx_runtime_1.jsx)(copy_js_1.default, 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.default,
span: copy_js_1.default,
a: link_js_1.default,
h2: (node, props, children) => {
var _a;
return ((0, jsx_runtime_1.jsx)(header_js_1.default, 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.default, 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.default, 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.default, 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]);
const theme = (0, styled_components_1.useTheme)();
return (hasFirstLoadFinished && ((0, jsx_runtime_1.jsxs)(SectionWrapper, Object.assign({ id: hashId, ref: article }, { children: [(0, jsx_runtime_1.jsxs)(HeaderWrapper, Object.assign({ "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.default, Object.assign({ size: (0, is_rebrand_js_1.default)(theme) ? 'xs' : 'lg' }, { children: title })), (0, jsx_runtime_1.jsx)(copy_js_1.default, Object.assign({ 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.default, { name: `actions/carrot-${isOpen ? 'up' : 'down'}` }) })] })), isOpen && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ArticleContent, Object.assign({ "data-testid": `article:content:${title}` }, { children: (0, exports.transformHTML)(content) })), (0, jsx_runtime_1.jsx)(author_card_js_1.default, { description: bio, img: image, imgAlt: authorName, name: authorName, title: jobTitle }), (0, jsx_runtime_1.jsxs)(CloseButton, Object.assign({ "data-testid": `close-article:${title}`, onClick: () => {
setIsOpen(false);
} }, { children: [(0, jsx_runtime_1.jsx)(copy_js_1.default, Object.assign({ light: true }, { children: "Close" })), (0, jsx_runtime_1.jsx)(icon_js_1.default, { name: "actions/carrot-up" })] }))] }))] }))));
};
exports.Article = Article;
exports.Article.propTypes = {
/** Should have name, bio, jobTitle and image properties */
author: prop_types_1.default.object,
/** Date that the article was written */
dateGmt: prop_types_1.default.string,
/** The whole article that is pulled from Wordpress (raw html) */
content: prop_types_1.default.string,
/** Date for the last time the article was updated */
modifiedGmt: prop_types_1.default.string,
/** Minified text for the article, in raw html */
excerpt: prop_types_1.default.string,
/** Title for the article */
title: prop_types_1.default.string,
/** Defining if the article should start open */
shouldStartOpen: prop_types_1.default.bool,
};
exports.default = exports.Article;
//# sourceMappingURL=article.js.map