UNPKG

@readr-media/react-election-widgets

Version:
268 lines (245 loc) 8.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = SeatsChart; var _styledComponents = _interopRequireDefault(require("styled-components")); var _react = require("react"); var _switch = _interopRequireDefault(require("./switch")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const partiesColor = [{ index: 1, name: '中國國民黨', colors: ['#183193', '#122F9A', '#3356D8', '#5478FF', '#89A2FF'] }, { index: 2, name: '民主進步黨', colors: ['#18513B', '#165642', '#337C65', '#5CB096', '#80D4BA'] }, { index: 3, name: '台灣民眾黨', colors: ['#0E879D', '#1BA2BF', '#47C1E3', '#80DDF1', '#AAF0FF'] }, { index: 4, name: '時代力量', colors: ['#C88F00', '#DDA310', '#F9BE01', '#FFDA7B', '#FFE7A8'] }, { index: 5, name: '台灣團結聯盟', colors: ['#633E09', '#693D00', '#AB6300', '#D28A27', '#F6BB6A'] }, { index: 6, name: '社會民主黨', colors: ['#A7093B', '#C90D4C', '#E7316E', '#FA5F93', '#FF86AE'] }, { index: 7, name: '勞動黨', colors: ['#8C1F18', '#9C241F', '#BC423D', '#D9716C', '#F6A39F'] }, { index: 8, name: '親民黨', colors: ['#DF5609', '#E25100', '#F27C0E', '#FE9634', '#FFAF64'] }, { index: 9, name: '台灣基進', colors: ['#77250E', '#952C11', '#A73F24', '#CE674C', '#DD856E'] }, { index: 10, name: '新黨', colors: ['#DCC603', '#EFD915', '#FFF500', '#FFFA81', '#FFFCA9'] }, { index: 11, name: '綠黨', colors: ['#3B920F', '#51C21C', '#77E046', '#9FFF73', '#69D437'] }, { index: 12, name: '無黨團結聯盟', colors: ['#600000', '#92001A', '#C20F51', '#DF4981', '#D18DA6'] }, { index: 998, name: '席次尚未確認', colors: ['#fff', '#fff', '#fff', '#fff', '#fff'] }, { index: 999, name: '無黨籍', colors: ['#272727', '#4A4A4A', '#666666', '#818181', '#B1B1B1'] }, { index: 1000, name: '其他政黨', colors: ['#634455', '#966982', '#958090', '#C3B4BD', '#E8DFE4'] }]; const getPartyColor = party => { var _partiesColor$find; const color = ((_partiesColor$find = partiesColor.find(partyColor => party === null || party === void 0 ? void 0 : party.startsWith(partyColor.name))) === null || _partiesColor$find === void 0 ? void 0 : _partiesColor$find.colors[2]) || partiesColor[partiesColor.length - 1].colors[2]; return color; }; const SeatsChartWrapper = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatsChartWrapper", componentId: "sc-adnr6q-0" })(["font-size:20px;line-height:29px;"]); const SeatsChartYear = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatsChartYear", componentId: "sc-adnr6q-1" })(["display:flex;align-items:center;justify-content:center;font-weight:700;line-height:120%;padding:12px 0;"]); const SeatsChartTitle = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatsChartTitle", componentId: "sc-adnr6q-2" })(["padding:20px 0;text-align:center;background-color:#afafaf;font-weight:700;line-height:120%;padding:12px 0;border-top:1px solid #000;border-bottom:1px solid #000;"]); const Wrapper = _styledComponents.default.div.withConfig({ displayName: "react-components__Wrapper", componentId: "sc-adnr6q-3" })(["position:relative;display:flex;flex-wrap:wrap;padding:40px 39px 74px;"]); const SeatWrapper = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatWrapper", componentId: "sc-adnr6q-4" })(["display:flex;align-items:center;justify-content:center;width:24px;height:24px;"]); const Seat = _styledComponents.default.div.withConfig({ displayName: "react-components__Seat", componentId: "sc-adnr6q-5" })(["width:20px;height:20px;background-color:", ";border:solid 1px #000;border-radius:50%;"], /** * @param {Object} props * @param {string} props.bgColor */ ({ bgColor }) => bgColor || '#fff'); const SeatInfo = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatInfo", componentId: "sc-adnr6q-6" })(["position:fixed;border-radius:6px;max-width:68px;padding:4px;background-color:#000;color:#fff;font-size:12px;line-height:17.8px;top:501px;left:91px;", ""], /** * @param {Object} props * @param {number[]} props.coordinate */ ({ coordinate }) => coordinate.length ? ` top: ${coordinate[1]}px; left: ${coordinate[0]}px; ` : ` display: none; `); const SeatsSwitchWrapper = _styledComponents.default.div.withConfig({ displayName: "react-components__SeatsSwitchWrapper", componentId: "sc-adnr6q-7" })(["position:absolute;top:0;left:0;width:100%;height:40px;display:flex;align-items:center;justify-content:center;gap:8px;"]); const SeatsSwitchOption = _styledComponents.default.span.withConfig({ displayName: "react-components__SeatsSwitchOption", componentId: "sc-adnr6q-8" })(["font-size:13px;", ""], /** * @param {Object} props * @param {boolean} props.isActive * */ ({ isActive }) => isActive && `font-weight: 900;`); function sortPartiesAndUndefinedParty(rawParties) { let parties = rawParties; const undefinedPartyIndex = parties.findIndex(party => party.label === '席次尚未確認'); if (undefinedPartyIndex !== -1) { const undefinedParty = parties.splice(undefinedPartyIndex, 1); parties.sort((a, b) => b.seats - a.seats); parties.push(undefinedParty[0]); } else { parties.sort((a, b) => b.seats - a.seats); } return parties; } /** * @typedef {Object} Party * @property {string} label * @property {number} seats * * @typedef {Object} SeatData * @property {Array<Party>} parties * * @typedef {Object} SeatSwitchInfo * @property {boolean} isOn - state to indicate whether the switch is on or off. * @property {string} onText - text for switch on. * @property {string} offText - text for switch off. * @property {(value: boolean) => void} onChange - callback to send switch changed event. * * @typedef {Object} SeatMeta * @property {string} componentTitle - title used for seat chart. * @property {number} year - year to show on seat chart. * @property {SeatSwitchInfo} switchInfo - switch info to show related UI and callback. * * * This seat chart only takes input to render, * the logic of the data processed will stay outside of it. * @param {Object} props * @param {SeatData} props.data * @param {SeatMeta} props.meta * @param {string} [props.className] * @returns {JSX.Element} */ function SeatsChart({ data, meta, className }) { const [hoverParty, setHoverParty] = (0, _react.useState)({ show: false, party: '', coordinate: [] }); const parties = (0, _react.useMemo)(() => { return sortPartiesAndUndefinedParty(data.parties && Array.isArray(data.parties) ? [...data.parties] : []); }, [data.parties]); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(SeatsChartWrapper, { className: className, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SeatsChartYear, { children: meta.year }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SeatsChartTitle, { children: meta.componentTitle }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(Wrapper, { children: [hoverParty.show && /*#__PURE__*/(0, _jsxRuntime.jsx)(SeatInfo, { coordinate: hoverParty.coordinate, children: hoverParty.party }), meta.switchInfo && /*#__PURE__*/(0, _jsxRuntime.jsxs)(SeatsSwitchWrapper, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SeatsSwitchOption, { isActive: !meta.switchInfo.isOn, children: meta.switchInfo.onText }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_switch.default, { isOn: meta.switchInfo.isOn, onChange: switchOn => { meta.switchInfo.onChange(switchOn); } }), /*#__PURE__*/(0, _jsxRuntime.jsx)(SeatsSwitchOption, { isActive: meta.switchInfo.isOn, children: meta.switchInfo.offText })] }), parties.reduce((total, party) => { const color = getPartyColor(party.label); return total.concat([...Array(party.seats)].map((empty, i) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(SeatWrapper, { onMouseOver: () => { setHoverParty(value => ({ ...value, show: true, party: party.label })); }, onMouseMove: e => { setHoverParty(value => ({ ...value, coordinate: [e.clientX + 15, e.clientY] })); }, onMouseLeave: () => { setHoverParty({ show: false, party: '', coordinate: [] }); }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Seat, { bgColor: color }) }, party.label + i); })); }, [])] })] }); }