@empoweredvote/ev-ui 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -103,10 +103,13 @@ function RadarChartCore({
103
103
  onReplaceTopic = () => {
104
104
  },
105
105
  size = 400,
106
+ labelFontSize = 13,
106
107
  padding = 80,
108
+ labelOffset = 52,
107
109
  tightFit = false,
108
110
  activeSpoke = null,
109
- writeIns = {}
111
+ writeIns = {},
112
+ darkMode = false
110
113
  }) {
111
114
  var _a;
112
115
  const radius = size / 2 - 40;
@@ -177,9 +180,25 @@ function RadarChartCore({
177
180
  acc[shortTitle] = userAdj > 10 || cmpAdj > 10;
178
181
  return acc;
179
182
  }, {});
180
- const sidePadding = 20;
181
- let tightTop = -sidePadding;
182
- let tightHeight = size + sidePadding * 2;
183
+ const labelMeta = spokes.map(([shortTitle], i) => {
184
+ const angle = 2 * Math.PI * i / numSpokes;
185
+ const lines = wrapLabel(shortTitle, 12);
186
+ const longestLineLen = lines.reduce((m, ln) => ln.length > m ? ln.length : m, 0);
187
+ const estimatedWidth = longestLineLen * labelFontSize * 0.55;
188
+ const sinA = Math.sin(angle);
189
+ const side = sinA < -0.1 ? "left" : sinA > 0.1 ? "right" : "center";
190
+ return { estimatedWidth, side };
191
+ });
192
+ const leftLabelWidths = labelMeta.filter((m) => m.side === "left").map((m) => m.estimatedWidth);
193
+ const rightLabelWidths = labelMeta.filter((m) => m.side === "right").map((m) => m.estimatedWidth);
194
+ const minPadding = 40;
195
+ const maxPadding = padding * 2;
196
+ const rawLeft = Math.min(Math.max(leftLabelWidths.length ? Math.max(...leftLabelWidths) + labelOffset : 0, minPadding), maxPadding);
197
+ const rawRight = Math.min(Math.max(rightLabelWidths.length ? Math.max(...rightLabelWidths) + labelOffset : 0, minPadding), maxPadding);
198
+ const sidePadding = Math.max(rawLeft, rawRight);
199
+ const verticalPadding = padding;
200
+ let tightTop = -verticalPadding;
201
+ let tightHeight = size + verticalPadding * 2;
183
202
  if (tightFit && numSpokes > 0) {
184
203
  let yMin = Infinity, yMax = -Infinity;
185
204
  for (let i = 0; i < numSpokes; i++) {
@@ -189,8 +208,9 @@ function RadarChartCore({
189
208
  if (y < yMin) yMin = y;
190
209
  if (y > yMax) yMax = y;
191
210
  }
192
- tightTop = yMin - sidePadding;
193
- tightHeight = yMax + sidePadding - tightTop;
211
+ const labelMargin = labelOffset + labelFontSize * 2.5;
212
+ tightTop = yMin - labelMargin;
213
+ tightHeight = yMax + labelMargin - tightTop;
194
214
  }
195
215
  const guidePolygons = [];
196
216
  for (let level = 1; level <= 5; level++) {
@@ -201,7 +221,7 @@ function RadarChartCore({
201
221
  ring.push(`${centerX + radius * scale * Math.sin(angle)},${centerY - radius * scale * Math.cos(angle)}`);
202
222
  }
203
223
  guidePolygons.push(
204
- /* @__PURE__ */ import_react.default.createElement("polygon", { key: level, points: ring.join(" "), fill: "none", stroke: "#ccc" })
224
+ /* @__PURE__ */ import_react.default.createElement("polygon", { key: level, points: ring.join(" "), fill: "none", stroke: darkMode ? "#555" : "#ccc" })
205
225
  );
206
226
  }
207
227
  const getStanceText = (shortTitle, value) => {
@@ -238,7 +258,7 @@ function RadarChartCore({
238
258
  y1: centerY,
239
259
  x2: endX,
240
260
  y2: endY,
241
- stroke: isUnanswered ? "#9ca3af" : "#aaa",
261
+ stroke: isUnanswered ? "#9ca3af" : darkMode ? "#bbb" : "#888",
242
262
  strokeDasharray: isUnanswered ? "4 3" : void 0,
243
263
  opacity: isUnanswered ? 0.6 : 1
244
264
  }
@@ -255,6 +275,39 @@ function RadarChartCore({
255
275
  }
256
276
  ));
257
277
  }),
278
+ spokes.map(([shortTitle], i) => {
279
+ const angle = 2 * Math.PI * i / numSpokes;
280
+ const cosA = Math.cos(angle);
281
+ const isBottom = cosA < -0.5;
282
+ const isTop = cosA > 0.5;
283
+ const lines = wrapLabel(shortTitle, 12);
284
+ const longestLine = lines.reduce((m, ln) => ln.length > m ? ln.length : m, 0);
285
+ const lineHeight = labelFontSize * 1.2;
286
+ const dynamicOffset = lines.length > 1 ? labelOffset + 6 : labelOffset;
287
+ const offset2 = radius + dynamicOffset;
288
+ const labelX = centerX + offset2 * Math.sin(angle);
289
+ let labelY = centerY - offset2 * Math.cos(angle);
290
+ if (isTop && lines.length > 1) labelY -= (lines.length - 1) * lineHeight;
291
+ const isActive = shortTitle === activeSpoke;
292
+ const isUnansweredLabel = !!unansweredSpokes[shortTitle];
293
+ const fSize = labelFontSize;
294
+ return /* @__PURE__ */ import_react.default.createElement(
295
+ "text",
296
+ {
297
+ key: `label-${shortTitle}`,
298
+ x: labelX,
299
+ y: labelY,
300
+ textAnchor: "middle",
301
+ dominantBaseline: isBottom ? "hanging" : "auto",
302
+ onClick: () => onReplaceTopic(shortTitle),
303
+ fill: isActive ? "#E85D26" : isUnansweredLabel ? "#9ca3af" : darkMode ? "#D3D7DE" : "#555",
304
+ fontWeight: isActive ? "bold" : "normal",
305
+ style: { cursor: "pointer", userSelect: "none", fontSize: fSize, fontFamily: "sans-serif" }
306
+ },
307
+ isUnansweredLabel && /* @__PURE__ */ import_react.default.createElement("title", null, "No stance on file for this topic."),
308
+ lines.map((ln, idx) => /* @__PURE__ */ import_react.default.createElement("tspan", { key: idx, x: labelX, dy: idx === 0 ? "0" : `${lineHeight}` }, ln))
309
+ );
310
+ }),
258
311
  countChanged ? /* @__PURE__ */ import_react.default.createElement(
259
312
  "polygon",
260
313
  {
@@ -369,14 +422,14 @@ function RadarChartCore({
369
422
  {
370
423
  xmlns: "http://www.w3.org/1999/xhtml",
371
424
  style: {
372
- background: "white",
373
- border: "1px solid #d1d5db",
374
- borderRadius: 6,
375
- padding: "6px 10px",
376
- fontSize: 11,
425
+ background: darkMode ? "#2F3237" : "#ffffff",
426
+ border: darkMode ? "1px solid #59B0C4" : "1px solid #d1d5db",
427
+ borderRadius: 8,
428
+ padding: "7px 11px",
429
+ fontSize: 12,
377
430
  lineHeight: 1.4,
378
- color: "#111",
379
- boxShadow: "0 2px 8px rgba(0,0,0,0.12)",
431
+ color: darkMode ? "#EBEDEF" : "#111",
432
+ boxShadow: darkMode ? "0 2px 12px rgba(0,0,0,0.4)" : "0 2px 8px rgba(0,0,0,0.12)",
380
433
  width: tipW + "px",
381
434
  wordWrap: "break-word"
382
435
  }
@@ -387,6 +440,37 @@ function RadarChartCore({
387
440
  })()
388
441
  );
389
442
  }
443
+ function wrapLabel(label, maxChars = 12) {
444
+ const str = String(label);
445
+ let rawWords;
446
+ if (str.includes("/")) {
447
+ rawWords = str.split("/").reduce((acc, segment, idx, arr) => {
448
+ const part = idx < arr.length - 1 ? segment + "/" : segment;
449
+ if (part.trim()) acc.push(part.trim());
450
+ return acc;
451
+ }, []);
452
+ } else {
453
+ rawWords = str.split(/\s+/);
454
+ }
455
+ const lines = [];
456
+ let line = "";
457
+ for (const word of rawWords) {
458
+ if (line === "") {
459
+ line = word;
460
+ } else if ((line + " " + word).length <= maxChars) {
461
+ line += " " + word;
462
+ } else {
463
+ lines.push(line);
464
+ line = word;
465
+ }
466
+ }
467
+ if (line) lines.push(line);
468
+ if (lines.length > 2) {
469
+ const overflow = lines.splice(2).join(" ");
470
+ lines[1] = lines[1] + " " + overflow;
471
+ }
472
+ return lines;
473
+ }
390
474
 
391
475
  // src/Header.jsx
392
476
  var import_react3 = __toESM(require("react"));