@readr-media/react-election-widgets
Version:
533 lines (469 loc) • 18.6 kB
JavaScript
"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
})]
});
}