UNPKG

@readr-media/react-election-widgets

Version:
533 lines (469 loc) 18.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = List; var _react = _interopRequireWildcard(require("react")); var _breakpoint = _interopRequireDefault(require("./breakpoint")); var _styledComponents = _interopRequireDefault(require("styled-components")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * @typedef {import('./typedef').District} District * @typedef {import('./typedef').Candidate} Candidate * @typedef {import('./manager').Row} Row * @typedef {import('./manager').Head} Head */ // eslint-disable-line const Table = _styledComponents.default.div.withConfig({ displayName: "list__Table", componentId: "sc-10n99f0-0" })(["display:table;font-weight:500;color:#0f2d35;font-size:16px;", ""], props => { var _props$theme; switch ((_props$theme = props.theme) === null || _props$theme === void 0 ? void 0 : _props$theme.device) { case 'mobile': { return ` width: 100%; display: flex; flex-wrap: nowrap; font-size: 14px; border-top: 1px solid black; border-bottom: 1px solid black; overflow: hidden; `; } case 'rwd': default: { return ` @media ${_breakpoint.default.devices.laptop} { width: 1200px; } @media ${_breakpoint.default.devices.laptopBelow} { width: 100%; display: flex; flex-wrap: nowrap; border-top: 1px solid black; border-bottom: 1px solid black; overflow: hidden; } @media ${_breakpoint.default.devices.tabletBelow} { font-size: 14px; } `; } } }); const TBody = _styledComponents.default.div.withConfig({ displayName: "list__TBody", componentId: "sc-10n99f0-1" })(["", ""], props => { var _props$theme2; switch ((_props$theme2 = props.theme) === null || _props$theme2 === void 0 ? void 0 : _props$theme2.device) { case 'mobile': { return ` position: relative; background-color: white; width: 100%; display: flex; flex-wrap: nowrap; overflow-x: scroll; overflow-y: hidden; scroll-behavior: smooth; `; } case 'rwd': default: { return ` @media ${_breakpoint.default.devices.laptop} { display: table-row-group; } @media ${_breakpoint.default.devices.laptopBelow} { /** * The reason we make \`TBody\` positioned is because we need it to * be an [\`offsetParent\`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent). * When user clicks go-to-specific-district button, * which will call \`setSelectedDistrictNumber\`, * and the program needs to automatically scroll to the specific district. * We need \`TBody\` to be positioned so that the district.\`offsetLeft\` will refer to * \`TBody\` rather than the viewport. **/ position: relative; background-color: white; width: 100%; display: flex; flex-wrap: nowrap; overflow-x: scroll; overflow-y: hidden; scroll-behavior: smooth; } @media ${_breakpoint.default.devices.tabletBelow} { } `; } } }); const TRow = _styledComponents.default.div.withConfig({ displayName: "list__TRow", componentId: "sc-10n99f0-2" })(["", ""], /** * @param {Object} props * @param {Object} [props.theme] * @param {string} [props.bgColorTheme] */ props => { var _props$theme3; switch ((_props$theme3 = props.theme) === null || _props$theme3 === void 0 ? void 0 : _props$theme3.device) { case 'mobile': { return ` flex-shrink: 0; `; } case 'rwd': default: { var _props$theme4, _props$theme4$table, _props$theme4$table$r, _props$theme5, _props$theme5$table, _props$theme5$table$r; return ` @media ${_breakpoint.default.devices.laptop} { display: table-row; background: ${(_props$theme4 = props.theme) !== null && _props$theme4 !== void 0 && (_props$theme4$table = _props$theme4.table) !== null && _props$theme4$table !== void 0 && (_props$theme4$table$r = _props$theme4$table.row) !== null && _props$theme4$table$r !== void 0 && _props$theme4$table$r.backgroundColor[props === null || props === void 0 ? void 0 : props.bgColorTheme] ? (_props$theme5 = props.theme) === null || _props$theme5 === void 0 ? void 0 : (_props$theme5$table = _props$theme5.table) === null || _props$theme5$table === void 0 ? void 0 : (_props$theme5$table$r = _props$theme5$table.row) === null || _props$theme5$table$r === void 0 ? void 0 : _props$theme5$table$r.backgroundColor[props === null || props === void 0 ? void 0 : props.bgColorTheme] : '#fff'} } @media ${_breakpoint.default.devices.laptopBelow} { flex-shrink: 0; } `; } } }); const TCell = _styledComponents.default.div.withConfig({ displayName: "list__TCell", componentId: "sc-10n99f0-3" })(["", ""], /** * @param {Object} props * @param {Object} props.theme * @param {boolean} [props.multiLines] */ props => { var _props$theme6, _props$theme6$table, _props$theme6$table$c, _props$theme6$table$c2, _props$theme7, _props$theme7$table, _props$theme7$table$c, _props$theme7$table$c2, _props$theme8, _props$theme8$table, _props$theme8$table$c, _props$theme8$table$c2, _props$theme9; const baseCss = ` position: relative; a { color: #d6610c; text-decoration: none; color: ${(_props$theme6 = props.theme) !== null && _props$theme6 !== void 0 && (_props$theme6$table = _props$theme6.table) !== null && _props$theme6$table !== void 0 && (_props$theme6$table$c = _props$theme6$table.candidate) !== null && _props$theme6$table$c !== void 0 && (_props$theme6$table$c2 = _props$theme6$table$c.name) !== null && _props$theme6$table$c2 !== void 0 && _props$theme6$table$c2.color ? (_props$theme7 = props.theme) === null || _props$theme7 === void 0 ? void 0 : (_props$theme7$table = _props$theme7.table) === null || _props$theme7$table === void 0 ? void 0 : (_props$theme7$table$c = _props$theme7$table.candidate) === null || _props$theme7$table$c === void 0 ? void 0 : (_props$theme7$table$c2 = _props$theme7$table$c.name) === null || _props$theme7$table$c2 === void 0 ? void 0 : _props$theme7$table$c2.color : '#000'}; pointer-events: ${(_props$theme8 = props.theme) !== null && _props$theme8 !== void 0 && (_props$theme8$table = _props$theme8.table) !== null && _props$theme8$table !== void 0 && (_props$theme8$table$c = _props$theme8$table.candidate) !== null && _props$theme8$table$c !== void 0 && (_props$theme8$table$c2 = _props$theme8$table$c.name) !== null && _props$theme8$table$c2 !== void 0 && _props$theme8$table$c2.isLink ? 'auto' : 'none'}; } `; switch ((_props$theme9 = props.theme) === null || _props$theme9 === void 0 ? void 0 : _props$theme9.device) { case 'mobile': { return ` ${baseCss} max-width: ${props.multiLines ? '187px' : 'none'}; padding: 15px; text-align: left; line-height: 150%; height: ${props.multiLines ? 'none' : '53px'}; border-left: 1px solid rgba(0, 0, 0, 0.1); &:first-child { border-left: none; } `; } case 'rwd': default: { return ` ${baseCss} @media ${_breakpoint.default.devices.laptop} { padding: 8px 30px; &:first-child { border-bottom: none; padding-left: 4px; } border-bottom: 1px solid rgba(0, 0, 0, 0.1); display: table-cell; vertical-align: middle; } @media ${_breakpoint.default.devices.laptopBelow} { padding: 15px; text-align: left; line-height: 150%; border-left: 1px solid rgba(0, 0, 0, 0.1); height: 56px; } @media ${_breakpoint.default.devices.tabletBelow} { height: none; } `; } } }); const THead = _styledComponents.default.div.withConfig({ displayName: "list__THead", componentId: "sc-10n99f0-4" })(["", ""], props => { var _props$theme10; const baseCss = ` background-color: ${props.theme.table.head.backgroundColor}; color: ${props.theme.table.head.color}; `; const mobileCss = ` border-right: 1px solid black; width: 96px; flex-shrink: 0; ${TRow} { flex-shrink: unset; } ${TCell} { text-align: right; } `; switch ((_props$theme10 = props.theme) === null || _props$theme10 === void 0 ? void 0 : _props$theme10.device) { case 'mobile': { return ` ${baseCss} ${mobileCss} `; } case 'rwd': default: { const stickyCss = props.theme.stickyTopOffset ? `position: sticky; top: ${props.theme.stickyTopOffset}` : ''; return ` ${baseCss} @media ${_breakpoint.default.devices.laptop} { display: table-header-group; border-bottom: 2px solid black; z-index: 2; ${TCell} { border-bottom: 2px solid black; } ${stickyCss} } @media ${_breakpoint.default.devices.laptopBelow} { ${mobileCss} } `; } } }); const EntityCell = _styledComponents.default.div.withConfig({ displayName: "list__EntityCell", componentId: "sc-10n99f0-5" })(["", ""], /** * @param {Object} props * @param {Object} props.theme * @param {boolean} [props.multiLines] */ props => { var _props$theme11; const baseCss = ` display: ${props.multiLines ? 'flex' : 'inline-flex'}; align-items: center; position: relative; > a { display: inline-flex; align-items: center; } span { margin-right: 22px; } `; const intervalTiltCss = ` &:not(:first-child):before { content: '/'; color: rgba(15, 45, 53, 0.3); font-size: 14px; font-weight: 700; position: absolute; top: 50%; left: -14px; transform: translateY(-50%); width: 6px; height: 21px; } `; const intervalEmptyCss = ` &:not(:first-child):before { content: ''; width: 0; height: 0; } `; switch ((_props$theme11 = props.theme) === null || _props$theme11 === void 0 ? void 0 : _props$theme11.device) { case 'mobile': { return ` ${baseCss} ${props.multiLines ? intervalEmptyCss : intervalTiltCss}; `; } case 'rwd': default: { return ` ${baseCss} ${props.multiLines ? intervalEmptyCss : intervalTiltCss}; @media ${_breakpoint.default.devices.laptop} { ${intervalEmptyCss} width: 100%; min-height: 52px; span { margin-right: 0px; } } `; } } }); const LegislatorPartyNotion = _styledComponents.default.span.withConfig({ displayName: "list__LegislatorPartyNotion", componentId: "sc-10n99f0-6" })(["", ""], /** * @param {Object} props * @param {Object} props.theme */ props => { var _props$theme12; const baseCss = ` position: absolute; color: rgba(15, 45, 53, 0.5); text-align: right; font-size: 10px; max-width: 60px; bottom: -8px; right: 15px; `; switch ((_props$theme12 = props.theme) === null || _props$theme12 === void 0 ? void 0 : _props$theme12.device) { case 'mobile': { return ` ${baseCss} line-height: 12px; `; } case 'rwd': default: { return ` ${baseCss} line-height: 14px; @media ${_breakpoint.default.devices.tablet} { bottom: -12px; } @media ${_breakpoint.default.devices.laptop} { font-size: 12px; top: -10px; right: 30px; max-width: none; } `; } } }); /** * @param {Object} props * @param {string} [props.className] * @param {import('./manager').DataManager} props.dataManager * @param {string} props.scrollTo */ function List({ className, dataManager, scrollTo }) { var _dataManager$findRowB, _rows$; const rows = dataManager.buildListRows(); const heads = dataManager.buildListHead(); const data = dataManager.getData(); const rowId = ((_dataManager$findRowB = dataManager.findRowByDistrictName(scrollTo)) === null || _dataManager$findRowB === void 0 ? void 0 : _dataManager$findRowB.id) ?? (rows === null || rows === void 0 ? void 0 : (_rows$ = rows[0]) === null || _rows$ === void 0 ? void 0 : _rows$.id) ?? 'row-1'; const tBodyRef = (0, _react.useRef)(null); const tableRef = (0, _react.useRef)(null); (0, _react.useEffect)(() => { const node = tBodyRef.current; // query the selected element according to district number const rowNode = node === null || node === void 0 ? void 0 : node.querySelector(`[data-row-id="${rowId}"]`); // get the number of pixels that the selected element's content is scrolled from its left edge const offsetLeft = (rowNode === null || rowNode === void 0 ? void 0 : rowNode.offsetLeft) ?? 0; // `setTimeout` is to avoid not scrolling on iOS device. setTimeout(() => { // scroll to the selected element node.scrollLeft = offsetLeft; }, 0); }, [scrollTo]); let previousBgColor = 'dark'; const rowsJsx = rows.map((row, rowIdx) => { const cellsJsx = row.cells.map((cell, cellIdx) => { var _row$cells, _row$cells$cellIdx, _row$cells$cellIdx$; let multiLines = false; const entitiesJsx = cell.map((entity, entityIdx) => { const imgJsx = (entity === null || entity === void 0 ? void 0 : entity.imgJsx) ?? null; const labelJsx = entity !== null && entity !== void 0 && entity.label ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { children: entity.label }) : null; const entityJsx = entity !== null && entity !== void 0 && entity.href ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("a", { href: entity.href, children: [imgJsx, labelJsx] }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [imgJsx, labelJsx] }); multiLines = entity.multiLines ?? false; return /*#__PURE__*/(0, _jsxRuntime.jsx)(EntityCell, { multiLines: multiLines, children: entityJsx }, entityIdx); }); return /*#__PURE__*/(0, _jsxRuntime.jsx)(TCell, { multiLines: multiLines, "data-multi-lines": multiLines, "data-column-id": cellIdx, style: ((_row$cells = row.cells) === null || _row$cells === void 0 ? void 0 : (_row$cells$cellIdx = _row$cells[cellIdx]) === null || _row$cells$cellIdx === void 0 ? void 0 : (_row$cells$cellIdx$ = _row$cells$cellIdx[0]) === null || _row$cells$cellIdx$ === void 0 ? void 0 : _row$cells$cellIdx$.label) === '' ? { borderLeft: 'none' } : undefined, children: entitiesJsx }, cellIdx); }); let currentBgColor = previousBgColor; const previousRow = rows === null || rows === void 0 ? void 0 : rows[rowIdx - 1]; if ((previousRow === null || previousRow === void 0 ? void 0 : previousRow.group) !== (row === null || row === void 0 ? void 0 : row.group)) { currentBgColor = previousBgColor === 'dark' ? 'light' : 'dark'; previousBgColor = currentBgColor; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(TRow, { "data-row-id": row.id, bgColorTheme: currentBgColor, children: cellsJsx }, row.id); }); // Since election-type `legislator-party` has `tksRate1`(第一階段投票率) & `tksRate2` data, but only need to show `tksRate1` and add notion: `*得票率=第一階段得票率`. // so it's necessary to determine the election type and whether the head is `得票率`. const shouldShowHeadNotion = Boolean((data === null || data === void 0 ? void 0 : data.type) === 'legislator-party'); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Table, { className: className, ref: tableRef, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(THead, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TRow, { bgColorTheme: "light", children: heads.map((head, idx) => { return /*#__PURE__*/(0, _jsxRuntime.jsxs)(TCell, { "data-column-id": idx, children: [head, shouldShowHeadNotion && head === '得票率' && /*#__PURE__*/(0, _jsxRuntime.jsx)(LegislatorPartyNotion, { children: "*\u5F97\u7968\u7387 = \u7B2C\u4E00\u968E\u6BB5\u5F97\u7968\u7387" })] }, `head_${idx}`); }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(TBody, { ref: tBodyRef, children: rowsJsx })] }); }