@behindthemusictree/genre-tree-view 5.0.0 → 6.2.0
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.cjs +467 -547
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -18
- package/dist/index.d.ts +15 -18
- package/dist/index.js +462 -542
- package/dist/index.js.map +1 -1
- package/dist/styles.css +71 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// src/GenreTree.tsx
|
|
2
2
|
import { useEffect as useEffect5, useRef as useRef5, useMemo as useMemo2 } from "react";
|
|
3
3
|
import * as d3 from "d3";
|
|
4
|
-
import { MdFitScreen, MdZoomIn as MdZoomIn2, MdZoomOut } from "react-icons/md";
|
|
5
4
|
|
|
6
5
|
// src/NodeHelper.tsx
|
|
7
6
|
import ReactDOMServer from "react-dom/server";
|
|
@@ -25,6 +24,9 @@ var MENU_WIDTH = 130;
|
|
|
25
24
|
var PER_TREE_ACCENT_DOT = true;
|
|
26
25
|
var ROOT_TINT_RATIO = 0.08;
|
|
27
26
|
var POP_SECTOR_TINT_RATIO = 0.8;
|
|
27
|
+
var UNDERGROUND_DARKEN_RATIO = 0.62;
|
|
28
|
+
var UNDERGROUND_SECTOR_FILL_OPACITY = 0.15;
|
|
29
|
+
var SCENE_SECTOR_OUTER_RADIUS = 1e5;
|
|
28
30
|
var CENTER_NODE_NAME = "Mainstream Pop";
|
|
29
31
|
var TREE_COLORS = [
|
|
30
32
|
"#4F46E5",
|
|
@@ -106,6 +108,11 @@ function isMainstreamPopLineage(index, nodeId) {
|
|
|
106
108
|
const topRoot = index.ancestorsOf(nodeId)[0] ?? index.byId.get(nodeId);
|
|
107
109
|
return topRoot?.name === CENTER_NODE_NAME;
|
|
108
110
|
}
|
|
111
|
+
function shadeSurface(hex, ratio) {
|
|
112
|
+
const channel = (offset) => parseInt(hex.slice(offset, offset + 2), 16);
|
|
113
|
+
const toHex = (value) => Math.round(value * ratio).toString(16).padStart(2, "0");
|
|
114
|
+
return `#${toHex(channel(1))}${toHex(channel(3))}${toHex(channel(5))}`;
|
|
115
|
+
}
|
|
109
116
|
function getGenreNodeStyle(index, nodeId) {
|
|
110
117
|
if (isMainstreamPopLineage(index, nodeId)) {
|
|
111
118
|
return { fill: tintSurface("#ffffff", POP_SECTOR_TINT_RATIO), textColor: TEXT_COLOR };
|
|
@@ -194,10 +201,13 @@ function calculateRootLabelFontSize(layoutFontSize, zoomScale) {
|
|
|
194
201
|
return Math.max(layoutFontSize, ROOT_LABEL_MIN_SCREEN_PX / zoomScale);
|
|
195
202
|
}
|
|
196
203
|
var NODE_DOT_MIN_RADIUS = 3;
|
|
197
|
-
var NODE_DOT_MAX_RADIUS =
|
|
204
|
+
var NODE_DOT_MAX_RADIUS = 24;
|
|
198
205
|
var NODE_DOT_LABEL_GAP = 6;
|
|
206
|
+
var NODE_LAYOUT_SLOT_RADIUS = 8;
|
|
199
207
|
function calculateNodeDotRadius(itemCount, range) {
|
|
200
|
-
|
|
208
|
+
const minArea = NODE_DOT_MIN_RADIUS ** 2;
|
|
209
|
+
const maxArea = NODE_DOT_MAX_RADIUS ** 2;
|
|
210
|
+
return Math.sqrt(minArea + logarithmicPosition(itemCount, range) * (maxArea - minArea));
|
|
201
211
|
}
|
|
202
212
|
var WHEEL_RADIUS = 260;
|
|
203
213
|
var WHEEL_VIEWPORT_HEIGHT = WHEEL_RADIUS * 2 + MAX_NODE_HEIGHT / 2;
|
|
@@ -584,6 +594,61 @@ function renderTree(d3Lib, svgRef, treeData, svgWidth, svgHeight, reparentingNod
|
|
|
584
594
|
return svg;
|
|
585
595
|
}
|
|
586
596
|
|
|
597
|
+
// src/FloatingControls.tsx
|
|
598
|
+
import { MdFitScreen, MdZoomIn, MdZoomOut } from "react-icons/md";
|
|
599
|
+
|
|
600
|
+
// src/BusyIndicator.tsx
|
|
601
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
602
|
+
function BusyIndicator() {
|
|
603
|
+
return /* @__PURE__ */ jsxs2("div", { className: "gtv-busy", role: "status", "aria-live": "polite", children: [
|
|
604
|
+
/* @__PURE__ */ jsx2("span", { className: "gtv-busy-ring", "aria-hidden": "true" }),
|
|
605
|
+
/* @__PURE__ */ jsx2("span", { className: "gtv-skeleton-sr-only", children: "Updating genre tree\u2026" })
|
|
606
|
+
] });
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// src/FloatingControls.tsx
|
|
610
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
611
|
+
function FloatingControls({ panZoom, onFit, orientation, leading, busy }) {
|
|
612
|
+
return /* @__PURE__ */ jsxs3(
|
|
613
|
+
"div",
|
|
614
|
+
{
|
|
615
|
+
className: [
|
|
616
|
+
"gtv-wheel-floating-controls",
|
|
617
|
+
orientation === "horizontal" && "gtv-wheel-floating-controls--horizontal"
|
|
618
|
+
].filter(Boolean).join(" "),
|
|
619
|
+
children: [
|
|
620
|
+
busy && /* @__PURE__ */ jsx3(BusyIndicator, {}),
|
|
621
|
+
leading && /* @__PURE__ */ jsx3("div", { className: "gtv-floating-controls-leading", children: leading }),
|
|
622
|
+
/* @__PURE__ */ jsxs3("div", { className: "gtv-zoom-controls", children: [
|
|
623
|
+
/* @__PURE__ */ jsx3(
|
|
624
|
+
"button",
|
|
625
|
+
{
|
|
626
|
+
type: "button",
|
|
627
|
+
className: ["gtv-zoom-btn", !panZoom.canZoomIn && "gtv-zoom-btn--disabled"].filter(Boolean).join(" "),
|
|
628
|
+
disabled: !panZoom.canZoomIn,
|
|
629
|
+
onClick: panZoom.zoomIn,
|
|
630
|
+
"aria-label": "Zoom in",
|
|
631
|
+
children: /* @__PURE__ */ jsx3(MdZoomIn, { className: "gtv-icon", size: 18 })
|
|
632
|
+
}
|
|
633
|
+
),
|
|
634
|
+
/* @__PURE__ */ jsx3(
|
|
635
|
+
"button",
|
|
636
|
+
{
|
|
637
|
+
type: "button",
|
|
638
|
+
className: ["gtv-zoom-btn", !panZoom.canZoomOut && "gtv-zoom-btn--disabled"].filter(Boolean).join(" "),
|
|
639
|
+
disabled: !panZoom.canZoomOut,
|
|
640
|
+
onClick: panZoom.zoomOut,
|
|
641
|
+
"aria-label": "Zoom out",
|
|
642
|
+
children: /* @__PURE__ */ jsx3(MdZoomOut, { className: "gtv-icon", size: 18 })
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "gtv-zoom-btn", onClick: onFit, "aria-label": "Fit to frame", children: /* @__PURE__ */ jsx3(MdFitScreen, { className: "gtv-icon", size: 18 }) })
|
|
646
|
+
] })
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
|
|
587
652
|
// src/use-pan-zoom.ts
|
|
588
653
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
589
654
|
|
|
@@ -1220,13 +1285,13 @@ function useTreeIndex(nodes) {
|
|
|
1220
1285
|
|
|
1221
1286
|
// src/InfoPanel.tsx
|
|
1222
1287
|
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
1223
|
-
import { MdArrowBack, MdClose, MdZoomIn } from "react-icons/md";
|
|
1288
|
+
import { MdArrowBack, MdClose, MdZoomIn as MdZoomIn2 } from "react-icons/md";
|
|
1224
1289
|
|
|
1225
1290
|
// src/InfoPanelExpandButton.tsx
|
|
1226
1291
|
import { MdCloseFullscreen, MdOpenInFull } from "react-icons/md";
|
|
1227
|
-
import { jsx as
|
|
1292
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1228
1293
|
function InfoPanelExpandButton({ expanded, onExpandedChange, style }) {
|
|
1229
|
-
return /* @__PURE__ */
|
|
1294
|
+
return /* @__PURE__ */ jsx4(
|
|
1230
1295
|
"button",
|
|
1231
1296
|
{
|
|
1232
1297
|
type: "button",
|
|
@@ -1234,7 +1299,7 @@ function InfoPanelExpandButton({ expanded, onExpandedChange, style }) {
|
|
|
1234
1299
|
style,
|
|
1235
1300
|
onClick: () => onExpandedChange(!expanded),
|
|
1236
1301
|
"aria-label": expanded ? "Collapse panel" : "Expand panel",
|
|
1237
|
-
children: expanded ? /* @__PURE__ */
|
|
1302
|
+
children: expanded ? /* @__PURE__ */ jsx4(MdCloseFullscreen, { className: "gtv-icon", size: 16 }) : /* @__PURE__ */ jsx4(MdOpenInFull, { className: "gtv-icon", size: 16 })
|
|
1238
1303
|
}
|
|
1239
1304
|
);
|
|
1240
1305
|
}
|
|
@@ -1242,11 +1307,11 @@ function InfoPanelExpandButton({ expanded, onExpandedChange, style }) {
|
|
|
1242
1307
|
// src/InfoPanelSection.tsx
|
|
1243
1308
|
import { useState as useState3 } from "react";
|
|
1244
1309
|
import { MdExpandMore } from "react-icons/md";
|
|
1245
|
-
import { jsx as
|
|
1310
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1246
1311
|
function InfoPanelSection({ title, children }) {
|
|
1247
1312
|
const [open, setOpen] = useState3(true);
|
|
1248
|
-
return /* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1313
|
+
return /* @__PURE__ */ jsxs4("div", { className: "gtv-info-panel-children", children: [
|
|
1314
|
+
/* @__PURE__ */ jsxs4(
|
|
1250
1315
|
"button",
|
|
1251
1316
|
{
|
|
1252
1317
|
type: "button",
|
|
@@ -1254,8 +1319,8 @@ function InfoPanelSection({ title, children }) {
|
|
|
1254
1319
|
"aria-expanded": open,
|
|
1255
1320
|
onClick: () => setOpen((isOpen) => !isOpen),
|
|
1256
1321
|
children: [
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1322
|
+
/* @__PURE__ */ jsx5("span", { className: "gtv-info-panel-children-title", children: title }),
|
|
1323
|
+
/* @__PURE__ */ jsx5(MdExpandMore, { className: "gtv-icon gtv-info-panel-section-chevron", size: 16 })
|
|
1259
1324
|
]
|
|
1260
1325
|
}
|
|
1261
1326
|
),
|
|
@@ -1268,7 +1333,7 @@ import { useState as useState4 } from "react";
|
|
|
1268
1333
|
import { MdMoreVert, MdModeEdit } from "react-icons/md";
|
|
1269
1334
|
import { FaPlus, FaTrashAlt, FaPlay, FaPause, FaSpinner } from "react-icons/fa";
|
|
1270
1335
|
import { PiGraphFill as PiGraphFill2 } from "react-icons/pi";
|
|
1271
|
-
import { Fragment, jsx as
|
|
1336
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1272
1337
|
function NodeToolbar({
|
|
1273
1338
|
node,
|
|
1274
1339
|
playingNodeId,
|
|
@@ -1289,9 +1354,9 @@ function NodeToolbar({
|
|
|
1289
1354
|
const isPlayable = node.itemCount > 0;
|
|
1290
1355
|
const isThisPlaying = playingNodeId === node.id;
|
|
1291
1356
|
const playLabel = isThisPlaying && playState === "playing" ? "Pause" : isThisPlaying && playState === "loading" ? "Loading..." : "Play";
|
|
1292
|
-
const playIcon = isThisPlaying && playState === "playing" ? /* @__PURE__ */
|
|
1293
|
-
return /* @__PURE__ */
|
|
1294
|
-
/* @__PURE__ */
|
|
1357
|
+
const playIcon = isThisPlaying && playState === "playing" ? /* @__PURE__ */ jsx6(FaPause, { className: "gtv-icon", size: "0.6em" }) : isThisPlaying && playState === "loading" ? /* @__PURE__ */ jsx6(FaSpinner, { className: "gtv-icon gtv-icon--spin", size: "0.6em" }) : /* @__PURE__ */ jsx6(FaPlay, { className: "gtv-icon", size: "0.6em" });
|
|
1358
|
+
return /* @__PURE__ */ jsxs5("div", { className: ["gtv-toolbar", className].filter(Boolean).join(" "), children: [
|
|
1359
|
+
/* @__PURE__ */ jsx6(
|
|
1295
1360
|
"button",
|
|
1296
1361
|
{
|
|
1297
1362
|
type: "button",
|
|
@@ -1303,8 +1368,8 @@ function NodeToolbar({
|
|
|
1303
1368
|
children: playIcon
|
|
1304
1369
|
}
|
|
1305
1370
|
),
|
|
1306
|
-
isActionable && /* @__PURE__ */
|
|
1307
|
-
/* @__PURE__ */
|
|
1371
|
+
isActionable && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1372
|
+
/* @__PURE__ */ jsx6(
|
|
1308
1373
|
"button",
|
|
1309
1374
|
{
|
|
1310
1375
|
type: "button",
|
|
@@ -1312,13 +1377,13 @@ function NodeToolbar({
|
|
|
1312
1377
|
title: "Add sub-genre",
|
|
1313
1378
|
"aria-label": "Add sub-genre",
|
|
1314
1379
|
onClick: () => onAddChild?.(node.id),
|
|
1315
|
-
children: /* @__PURE__ */
|
|
1380
|
+
children: /* @__PURE__ */ jsx6(FaPlus, { className: "gtv-icon", size: "0.6em" })
|
|
1316
1381
|
}
|
|
1317
1382
|
),
|
|
1318
1383
|
primaryExtraActions.map((action) => {
|
|
1319
1384
|
const enabled = action.enabled ? action.enabled(node) : true;
|
|
1320
1385
|
const label = action.label(node);
|
|
1321
|
-
return /* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsx6(
|
|
1322
1387
|
"button",
|
|
1323
1388
|
{
|
|
1324
1389
|
type: "button",
|
|
@@ -1332,8 +1397,8 @@ function NodeToolbar({
|
|
|
1332
1397
|
action.key
|
|
1333
1398
|
);
|
|
1334
1399
|
}),
|
|
1335
|
-
/* @__PURE__ */
|
|
1336
|
-
/* @__PURE__ */
|
|
1400
|
+
/* @__PURE__ */ jsxs5("div", { className: "gtv-toolbar-overflow", children: [
|
|
1401
|
+
/* @__PURE__ */ jsx6(
|
|
1337
1402
|
"button",
|
|
1338
1403
|
{
|
|
1339
1404
|
type: "button",
|
|
@@ -1343,11 +1408,11 @@ function NodeToolbar({
|
|
|
1343
1408
|
"aria-haspopup": "menu",
|
|
1344
1409
|
"aria-expanded": menuOpen,
|
|
1345
1410
|
onClick: () => setMenuOpen((open) => !open),
|
|
1346
|
-
children: /* @__PURE__ */
|
|
1411
|
+
children: /* @__PURE__ */ jsx6(MdMoreVert, { size: "0.6em" })
|
|
1347
1412
|
}
|
|
1348
1413
|
),
|
|
1349
|
-
menuOpen && /* @__PURE__ */
|
|
1350
|
-
/* @__PURE__ */
|
|
1414
|
+
menuOpen && /* @__PURE__ */ jsxs5("div", { className: "gtv-menu-card gtv-toolbar-overflow-menu", children: [
|
|
1415
|
+
/* @__PURE__ */ jsxs5(
|
|
1351
1416
|
"button",
|
|
1352
1417
|
{
|
|
1353
1418
|
type: "button",
|
|
@@ -1357,12 +1422,12 @@ function NodeToolbar({
|
|
|
1357
1422
|
onRenameRequest?.(node);
|
|
1358
1423
|
},
|
|
1359
1424
|
children: [
|
|
1360
|
-
/* @__PURE__ */
|
|
1361
|
-
/* @__PURE__ */
|
|
1425
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-icon", children: /* @__PURE__ */ jsx6(MdModeEdit, { className: "gtv-icon", size: 13 }) }),
|
|
1426
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-label", children: "Rename" })
|
|
1362
1427
|
]
|
|
1363
1428
|
}
|
|
1364
1429
|
),
|
|
1365
|
-
/* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsxs5(
|
|
1366
1431
|
"button",
|
|
1367
1432
|
{
|
|
1368
1433
|
type: "button",
|
|
@@ -1372,14 +1437,14 @@ function NodeToolbar({
|
|
|
1372
1437
|
onReparentRequest?.(node);
|
|
1373
1438
|
},
|
|
1374
1439
|
children: [
|
|
1375
|
-
/* @__PURE__ */
|
|
1376
|
-
/* @__PURE__ */
|
|
1440
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-icon", children: /* @__PURE__ */ jsx6(PiGraphFill2, { className: "gtv-icon", size: 13 }) }),
|
|
1441
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-label", children: "Change parent" })
|
|
1377
1442
|
]
|
|
1378
1443
|
}
|
|
1379
1444
|
),
|
|
1380
1445
|
overflowExtraActions.map((action) => {
|
|
1381
1446
|
const enabled = action.enabled ? action.enabled(node) : true;
|
|
1382
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsxs5(
|
|
1383
1448
|
"button",
|
|
1384
1449
|
{
|
|
1385
1450
|
type: "button",
|
|
@@ -1390,15 +1455,15 @@ function NodeToolbar({
|
|
|
1390
1455
|
action.onClick(event, node);
|
|
1391
1456
|
},
|
|
1392
1457
|
children: [
|
|
1393
|
-
/* @__PURE__ */
|
|
1394
|
-
/* @__PURE__ */
|
|
1458
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-icon", children: action.icon(node) }),
|
|
1459
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-label", children: action.label(node) })
|
|
1395
1460
|
]
|
|
1396
1461
|
},
|
|
1397
1462
|
action.key
|
|
1398
1463
|
);
|
|
1399
1464
|
}),
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
/* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsx6("div", { className: "gtv-menu-divider" }),
|
|
1466
|
+
/* @__PURE__ */ jsxs5(
|
|
1402
1467
|
"button",
|
|
1403
1468
|
{
|
|
1404
1469
|
type: "button",
|
|
@@ -1408,8 +1473,8 @@ function NodeToolbar({
|
|
|
1408
1473
|
onDeleteRequest?.(node);
|
|
1409
1474
|
},
|
|
1410
1475
|
children: [
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1476
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-icon", children: /* @__PURE__ */ jsx6(FaTrashAlt, { className: "gtv-icon", size: 13 }) }),
|
|
1477
|
+
/* @__PURE__ */ jsx6("span", { className: "gtv-menu-row-label", children: "Delete" })
|
|
1413
1478
|
]
|
|
1414
1479
|
}
|
|
1415
1480
|
)
|
|
@@ -1420,7 +1485,7 @@ function NodeToolbar({
|
|
|
1420
1485
|
}
|
|
1421
1486
|
|
|
1422
1487
|
// src/InfoPanel.tsx
|
|
1423
|
-
import { Fragment as Fragment2, jsx as
|
|
1488
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1424
1489
|
var MINI_NODE_MIN_DIAMETER = 14;
|
|
1425
1490
|
var MINI_NODE_MAX_DIAMETER = 32;
|
|
1426
1491
|
var MINI_NODE_MIN_FONT_SIZE = 10;
|
|
@@ -1452,10 +1517,6 @@ function InfoPanel({
|
|
|
1452
1517
|
onZoomIn,
|
|
1453
1518
|
actions,
|
|
1454
1519
|
readOnly = false,
|
|
1455
|
-
editMode = false,
|
|
1456
|
-
onEditModeChange,
|
|
1457
|
-
renderTitleEditor,
|
|
1458
|
-
renderParentsEditor,
|
|
1459
1520
|
renderDangerZone,
|
|
1460
1521
|
expanded = false,
|
|
1461
1522
|
onExpandedChange,
|
|
@@ -1466,10 +1527,8 @@ function InfoPanel({
|
|
|
1466
1527
|
useEffect3(() => {
|
|
1467
1528
|
panelRef.current?.toggleAttribute("inert", collapsed);
|
|
1468
1529
|
}, [collapsed]);
|
|
1469
|
-
const editing = editMode && !readOnly;
|
|
1470
|
-
const shownParent = editing && renderParentsEditor ? null : parentNode;
|
|
1471
1530
|
const miniTreeRange = getItemCountRange([
|
|
1472
|
-
...
|
|
1531
|
+
...parentNode ? [parentNode.node] : [],
|
|
1473
1532
|
node,
|
|
1474
1533
|
...childNodes.map((child) => child.node)
|
|
1475
1534
|
]);
|
|
@@ -1483,9 +1542,9 @@ function InfoPanel({
|
|
|
1483
1542
|
};
|
|
1484
1543
|
const miniNodeContent = (target, background, range) => {
|
|
1485
1544
|
const { diameter, fontSize } = miniNodeSize(target, range);
|
|
1486
|
-
return /* @__PURE__ */
|
|
1487
|
-
/* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1545
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1546
|
+
/* @__PURE__ */ jsx7("span", { className: "gtv-info-panel-mini-dot", style: { background, width: diameter, height: diameter } }),
|
|
1547
|
+
/* @__PURE__ */ jsx7("span", { className: "gtv-info-panel-mini-label", style: { fontSize }, children: target.name })
|
|
1489
1548
|
] });
|
|
1490
1549
|
};
|
|
1491
1550
|
const sortedChildNodes = [...childNodes].sort((a, b) => b.node.itemCount - a.node.itemCount);
|
|
@@ -1498,9 +1557,9 @@ function InfoPanel({
|
|
|
1498
1557
|
document.addEventListener("keydown", onKeyDown);
|
|
1499
1558
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1500
1559
|
}, [expanded, onExpandedChange]);
|
|
1501
|
-
const dangerZone =
|
|
1502
|
-
const toolbar = actions ? /* @__PURE__ */
|
|
1503
|
-
const ancestors = ancestorNodes.length > 0 ? /* @__PURE__ */
|
|
1560
|
+
const dangerZone = !readOnly && renderDangerZone && /* @__PURE__ */ jsx7("div", { className: "gtv-info-panel-danger-zone", children: renderDangerZone(node) });
|
|
1561
|
+
const toolbar = actions ? /* @__PURE__ */ jsx7(NodeToolbar, { node, className: "gtv-info-panel-toolbar", ...actions }, node.id) : null;
|
|
1562
|
+
const ancestors = ancestorNodes.length > 0 ? /* @__PURE__ */ jsx7(InfoPanelSection, { title: "Ancestors", children: /* @__PURE__ */ jsx7("ul", { className: "gtv-info-panel-children-list gtv-info-panel-ancestors-list", children: ancestorNodes.map(({ node: ancestor, fill: fill2 }) => /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
|
|
1504
1563
|
"button",
|
|
1505
1564
|
{
|
|
1506
1565
|
type: "button",
|
|
@@ -1510,76 +1569,73 @@ function InfoPanel({
|
|
|
1510
1569
|
children: miniNodeContent(ancestor, fill2, ancestorRange)
|
|
1511
1570
|
}
|
|
1512
1571
|
) }, ancestor.id)) }) }) : null;
|
|
1513
|
-
const family = /* @__PURE__ */
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1572
|
+
const family = /* @__PURE__ */ jsx7(Fragment2, { children: /* @__PURE__ */ jsx7(InfoPanelSection, { title: "Family", children: /* @__PURE__ */ jsxs6("div", { className: "gtv-info-panel-mini-tree", children: [
|
|
1573
|
+
parentNode && /* @__PURE__ */ jsx7("div", { className: "gtv-info-panel-mini-tree-parent", children: /* @__PURE__ */ jsx7(
|
|
1574
|
+
"button",
|
|
1575
|
+
{
|
|
1576
|
+
type: "button",
|
|
1577
|
+
className: "gtv-info-panel-child",
|
|
1578
|
+
title: parentNode.node.name,
|
|
1579
|
+
onClick: () => onSelectNode(parentNode.node.id),
|
|
1580
|
+
children: miniNodeContent(parentNode.node, parentNode.fill, miniTreeRange)
|
|
1581
|
+
}
|
|
1582
|
+
) }),
|
|
1583
|
+
/* @__PURE__ */ jsx7(
|
|
1584
|
+
"div",
|
|
1585
|
+
{
|
|
1586
|
+
className: `gtv-info-panel-mini-tree-node${childNodes.length === 0 ? " gtv-info-panel-mini-tree-node--leaf" : ""}`,
|
|
1587
|
+
children: /* @__PURE__ */ jsx7(
|
|
1588
|
+
"span",
|
|
1589
|
+
{
|
|
1590
|
+
className: "gtv-info-panel-child gtv-info-panel-mini-tree-current",
|
|
1591
|
+
title: node.name,
|
|
1592
|
+
children: miniNodeContent(node, fill, miniTreeRange)
|
|
1593
|
+
}
|
|
1594
|
+
)
|
|
1595
|
+
}
|
|
1596
|
+
),
|
|
1597
|
+
/* @__PURE__ */ jsxs6("div", { className: "gtv-info-panel-mini-tree-children", children: [
|
|
1598
|
+
/* @__PURE__ */ jsxs6("span", { className: "gtv-info-panel-children-title", children: [
|
|
1599
|
+
childNodes.length,
|
|
1600
|
+
" ",
|
|
1601
|
+
childNodes.length <= 1 ? "child" : "children"
|
|
1602
|
+
] }),
|
|
1603
|
+
childNodes.length > 0 && /* @__PURE__ */ jsx7("ul", { className: "gtv-info-panel-children-list", children: sortedChildNodes.map(({ node: child, fill: fill2 }) => /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(
|
|
1517
1604
|
"button",
|
|
1518
1605
|
{
|
|
1519
1606
|
type: "button",
|
|
1520
1607
|
className: "gtv-info-panel-child",
|
|
1521
|
-
title:
|
|
1522
|
-
onClick: () => onSelectNode(
|
|
1523
|
-
children: miniNodeContent(
|
|
1524
|
-
}
|
|
1525
|
-
) }),
|
|
1526
|
-
/* @__PURE__ */ jsx5(
|
|
1527
|
-
"div",
|
|
1528
|
-
{
|
|
1529
|
-
className: `gtv-info-panel-mini-tree-node${childNodes.length === 0 ? " gtv-info-panel-mini-tree-node--leaf" : ""}`,
|
|
1530
|
-
children: /* @__PURE__ */ jsx5(
|
|
1531
|
-
"span",
|
|
1532
|
-
{
|
|
1533
|
-
className: "gtv-info-panel-child gtv-info-panel-mini-tree-current",
|
|
1534
|
-
title: node.name,
|
|
1535
|
-
children: miniNodeContent(node, fill, miniTreeRange)
|
|
1536
|
-
}
|
|
1537
|
-
)
|
|
1608
|
+
title: child.name,
|
|
1609
|
+
onClick: () => onSelectNode(child.id),
|
|
1610
|
+
children: miniNodeContent(child, fill2, miniTreeRange)
|
|
1538
1611
|
}
|
|
1539
|
-
),
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
] }),
|
|
1546
|
-
childNodes.length > 0 && /* @__PURE__ */ jsx5("ul", { className: "gtv-info-panel-children-list", children: sortedChildNodes.map(({ node: child, fill: fill2 }) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5(
|
|
1547
|
-
"button",
|
|
1548
|
-
{
|
|
1549
|
-
type: "button",
|
|
1550
|
-
className: "gtv-info-panel-child",
|
|
1551
|
-
title: child.name,
|
|
1552
|
-
onClick: () => onSelectNode(child.id),
|
|
1553
|
-
children: miniNodeContent(child, fill2, miniTreeRange)
|
|
1554
|
-
}
|
|
1555
|
-
) }, child.id)) })
|
|
1556
|
-
] })
|
|
1557
|
-
] }) })
|
|
1558
|
-
] });
|
|
1559
|
-
const itemCount = /* @__PURE__ */ jsxs4("dl", { className: "gtv-info-panel-fields", children: [
|
|
1560
|
-
/* @__PURE__ */ jsx5("dt", { children: itemCountLabel }),
|
|
1561
|
-
/* @__PURE__ */ jsx5("dd", { children: node.itemCount })
|
|
1612
|
+
) }, child.id)) })
|
|
1613
|
+
] })
|
|
1614
|
+
] }) }) });
|
|
1615
|
+
const itemCount = /* @__PURE__ */ jsxs6("dl", { className: "gtv-info-panel-fields", children: [
|
|
1616
|
+
/* @__PURE__ */ jsx7("dt", { children: itemCountLabel }),
|
|
1617
|
+
/* @__PURE__ */ jsx7("dd", { children: node.itemCount })
|
|
1562
1618
|
] });
|
|
1563
|
-
const { primary, aside } = renderInfoPanelBody ? renderInfoPanelBody(node, { toolbar, ancestors, family, itemCount }) : { primary: /* @__PURE__ */
|
|
1619
|
+
const { primary, aside } = renderInfoPanelBody ? renderInfoPanelBody(node, { toolbar, ancestors, family, itemCount }) : { primary: /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1564
1620
|
toolbar,
|
|
1565
1621
|
ancestors,
|
|
1566
1622
|
family,
|
|
1567
1623
|
itemCount
|
|
1568
1624
|
] }) };
|
|
1569
1625
|
const hasAside = aside !== void 0 && aside !== null && aside !== false;
|
|
1570
|
-
return /* @__PURE__ */
|
|
1626
|
+
return /* @__PURE__ */ jsxs6(
|
|
1571
1627
|
"div",
|
|
1572
1628
|
{
|
|
1573
1629
|
className: `gtv-info-panel gtv-info-panel--${side}${expanded ? " gtv-info-panel--expanded" : ""}${expanded && !hasAside ? " gtv-info-panel--expanded-solo" : ""}${collapsed ? " gtv-info-panel--collapsed" : ""}`,
|
|
1574
1630
|
ref: panelRef,
|
|
1575
1631
|
children: [
|
|
1576
|
-
/* @__PURE__ */
|
|
1632
|
+
/* @__PURE__ */ jsxs6(
|
|
1577
1633
|
"div",
|
|
1578
1634
|
{
|
|
1579
1635
|
className: "gtv-info-panel-header",
|
|
1580
1636
|
style: { background: fill, color: textColor },
|
|
1581
1637
|
children: [
|
|
1582
|
-
onPrevious && /* @__PURE__ */
|
|
1638
|
+
onPrevious && /* @__PURE__ */ jsx7(
|
|
1583
1639
|
"button",
|
|
1584
1640
|
{
|
|
1585
1641
|
type: "button",
|
|
@@ -1588,21 +1644,21 @@ function InfoPanel({
|
|
|
1588
1644
|
onClick: onPrevious,
|
|
1589
1645
|
"aria-label": previousLabel ? `Previous: ${previousLabel}` : "Previous",
|
|
1590
1646
|
title: previousLabel,
|
|
1591
|
-
children: /* @__PURE__ */
|
|
1647
|
+
children: /* @__PURE__ */ jsx7(MdArrowBack, { className: "gtv-icon", size: 16 })
|
|
1592
1648
|
}
|
|
1593
1649
|
),
|
|
1594
|
-
|
|
1650
|
+
/* @__PURE__ */ jsxs6(
|
|
1595
1651
|
"span",
|
|
1596
1652
|
{
|
|
1597
1653
|
className: `gtv-info-panel-title${hideTitle ? " gtv-info-panel-title--hidden" : ""}`,
|
|
1598
1654
|
style: { color: textColor },
|
|
1599
1655
|
children: [
|
|
1600
1656
|
node.name,
|
|
1601
|
-
node.umbrella && /* @__PURE__ */
|
|
1657
|
+
node.umbrella && /* @__PURE__ */ jsx7("span", { className: "gtv-info-panel-umbrella-badge", children: "umbrella" })
|
|
1602
1658
|
]
|
|
1603
1659
|
}
|
|
1604
1660
|
),
|
|
1605
|
-
onZoomIn && /* @__PURE__ */
|
|
1661
|
+
onZoomIn && /* @__PURE__ */ jsx7(
|
|
1606
1662
|
"button",
|
|
1607
1663
|
{
|
|
1608
1664
|
type: "button",
|
|
@@ -1611,22 +1667,11 @@ function InfoPanel({
|
|
|
1611
1667
|
onClick: onZoomIn,
|
|
1612
1668
|
"aria-label": "Zoom in",
|
|
1613
1669
|
title: "Zoom in",
|
|
1614
|
-
children: /* @__PURE__ */
|
|
1615
|
-
}
|
|
1616
|
-
),
|
|
1617
|
-
onEditModeChange && !readOnly && /* @__PURE__ */ jsx5(
|
|
1618
|
-
"button",
|
|
1619
|
-
{
|
|
1620
|
-
type: "button",
|
|
1621
|
-
className: "gtv-info-panel-edit",
|
|
1622
|
-
style: { color: textColor },
|
|
1623
|
-
onClick: () => onEditModeChange(!editMode),
|
|
1624
|
-
"aria-pressed": editMode,
|
|
1625
|
-
children: editMode ? "Done" : "Edit"
|
|
1670
|
+
children: /* @__PURE__ */ jsx7(MdZoomIn2, { className: "gtv-icon", size: 16 })
|
|
1626
1671
|
}
|
|
1627
1672
|
),
|
|
1628
|
-
onExpandedChange && !hideExpandButton && /* @__PURE__ */
|
|
1629
|
-
!hideClose && /* @__PURE__ */
|
|
1673
|
+
onExpandedChange && !hideExpandButton && /* @__PURE__ */ jsx7(InfoPanelExpandButton, { expanded, onExpandedChange, style: { color: textColor } }),
|
|
1674
|
+
!hideClose && /* @__PURE__ */ jsx7(
|
|
1630
1675
|
"button",
|
|
1631
1676
|
{
|
|
1632
1677
|
type: "button",
|
|
@@ -1634,18 +1679,18 @@ function InfoPanel({
|
|
|
1634
1679
|
style: { color: textColor },
|
|
1635
1680
|
onClick: onClose,
|
|
1636
1681
|
"aria-label": "Close",
|
|
1637
|
-
children: /* @__PURE__ */
|
|
1682
|
+
children: /* @__PURE__ */ jsx7(MdClose, { className: "gtv-icon", size: 16 })
|
|
1638
1683
|
}
|
|
1639
1684
|
)
|
|
1640
1685
|
]
|
|
1641
1686
|
}
|
|
1642
1687
|
),
|
|
1643
|
-
/* @__PURE__ */
|
|
1644
|
-
/* @__PURE__ */
|
|
1688
|
+
/* @__PURE__ */ jsxs6("div", { className: "gtv-info-panel-body", children: [
|
|
1689
|
+
/* @__PURE__ */ jsxs6("div", { className: "gtv-info-panel-primary", children: [
|
|
1645
1690
|
primary,
|
|
1646
1691
|
expanded && !hasAside && dangerZone
|
|
1647
1692
|
] }),
|
|
1648
|
-
hasAside && /* @__PURE__ */
|
|
1693
|
+
hasAside && /* @__PURE__ */ jsxs6("div", { className: "gtv-info-panel-aside", children: [
|
|
1649
1694
|
aside,
|
|
1650
1695
|
expanded && dangerZone
|
|
1651
1696
|
] })
|
|
@@ -1659,7 +1704,7 @@ function InfoPanel({
|
|
|
1659
1704
|
// src/OverlayPanel.tsx
|
|
1660
1705
|
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
1661
1706
|
import { MdClose as MdClose2 } from "react-icons/md";
|
|
1662
|
-
import { jsx as
|
|
1707
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1663
1708
|
function OverlayPanel({
|
|
1664
1709
|
title,
|
|
1665
1710
|
content,
|
|
@@ -1694,21 +1739,21 @@ function OverlayPanel({
|
|
|
1694
1739
|
expanded && !extraContent && "gtv-info-panel--expanded-solo",
|
|
1695
1740
|
collapsed && "gtv-info-panel--collapsed"
|
|
1696
1741
|
].filter(Boolean).join(" ");
|
|
1697
|
-
return /* @__PURE__ */
|
|
1698
|
-
/* @__PURE__ */
|
|
1699
|
-
/* @__PURE__ */
|
|
1700
|
-
onExpandedChange && !hideExpandButton && /* @__PURE__ */
|
|
1701
|
-
!hideClose && /* @__PURE__ */
|
|
1742
|
+
return /* @__PURE__ */ jsxs7("div", { className, ref: panelRef, children: [
|
|
1743
|
+
/* @__PURE__ */ jsxs7("div", { className: "gtv-info-panel-header", children: [
|
|
1744
|
+
/* @__PURE__ */ jsx8("span", { className: `gtv-info-panel-title${hideTitle ? " gtv-info-panel-title--hidden" : ""}`, children: title }),
|
|
1745
|
+
onExpandedChange && !hideExpandButton && /* @__PURE__ */ jsx8(InfoPanelExpandButton, { expanded, onExpandedChange }),
|
|
1746
|
+
!hideClose && /* @__PURE__ */ jsx8("button", { type: "button", className: "gtv-info-panel-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx8(MdClose2, { className: "gtv-icon", size: 16 }) })
|
|
1702
1747
|
] }),
|
|
1703
|
-
/* @__PURE__ */
|
|
1704
|
-
/* @__PURE__ */
|
|
1705
|
-
extraContent && /* @__PURE__ */
|
|
1748
|
+
/* @__PURE__ */ jsxs7("div", { className: "gtv-info-panel-body", children: [
|
|
1749
|
+
/* @__PURE__ */ jsx8("div", { className: "gtv-info-panel-aside gtv-overlay-content", children: content }),
|
|
1750
|
+
extraContent && /* @__PURE__ */ jsx8("div", { className: "gtv-info-panel-primary gtv-overlay-content", children: extraContent })
|
|
1706
1751
|
] })
|
|
1707
1752
|
] });
|
|
1708
1753
|
}
|
|
1709
1754
|
|
|
1710
1755
|
// src/GenreTree.tsx
|
|
1711
|
-
import { jsx as
|
|
1756
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1712
1757
|
function GenreTree({
|
|
1713
1758
|
nodes,
|
|
1714
1759
|
className,
|
|
@@ -1736,10 +1781,6 @@ function GenreTree({
|
|
|
1736
1781
|
hideInfoPanelTitle = false,
|
|
1737
1782
|
itemCountLabel,
|
|
1738
1783
|
readOnly,
|
|
1739
|
-
editMode,
|
|
1740
|
-
onEditModeChange,
|
|
1741
|
-
renderTitleEditor,
|
|
1742
|
-
renderParentsEditor,
|
|
1743
1784
|
renderDangerZone,
|
|
1744
1785
|
expanded,
|
|
1745
1786
|
onExpandedChange,
|
|
@@ -1749,7 +1790,9 @@ function GenreTree({
|
|
|
1749
1790
|
wheelZoom,
|
|
1750
1791
|
defaultViewport,
|
|
1751
1792
|
onViewportChange,
|
|
1752
|
-
controlsOrientation = "vertical"
|
|
1793
|
+
controlsOrientation = "vertical",
|
|
1794
|
+
floatingControlsLeading,
|
|
1795
|
+
busy
|
|
1753
1796
|
}) {
|
|
1754
1797
|
const index = useTreeIndex(nodes);
|
|
1755
1798
|
const svgRef = useRef5(null);
|
|
@@ -1905,7 +1948,7 @@ function GenreTree({
|
|
|
1905
1948
|
hasInitialFitRef.current = true;
|
|
1906
1949
|
panZoom.fitToFrame(elements, { silent: true });
|
|
1907
1950
|
});
|
|
1908
|
-
const svg = /* @__PURE__ */
|
|
1951
|
+
const svg = /* @__PURE__ */ jsx9(
|
|
1909
1952
|
"svg",
|
|
1910
1953
|
{
|
|
1911
1954
|
ref: svgRef,
|
|
@@ -1915,13 +1958,14 @@ function GenreTree({
|
|
|
1915
1958
|
}
|
|
1916
1959
|
);
|
|
1917
1960
|
if (!interactive) {
|
|
1918
|
-
return /* @__PURE__ */
|
|
1961
|
+
return /* @__PURE__ */ jsx9("div", { className, children: svg });
|
|
1919
1962
|
}
|
|
1920
|
-
return /* @__PURE__ */
|
|
1963
|
+
return /* @__PURE__ */ jsxs8(
|
|
1921
1964
|
"div",
|
|
1922
1965
|
{
|
|
1923
1966
|
ref: viewportRef,
|
|
1924
1967
|
className,
|
|
1968
|
+
"aria-busy": busy,
|
|
1925
1969
|
style: {
|
|
1926
1970
|
position: "relative",
|
|
1927
1971
|
overflow: "hidden",
|
|
@@ -1944,7 +1988,7 @@ function GenreTree({
|
|
|
1944
1988
|
},
|
|
1945
1989
|
onPointerDown: panZoom.handlePointerDown,
|
|
1946
1990
|
children: [
|
|
1947
|
-
/* @__PURE__ */
|
|
1991
|
+
/* @__PURE__ */ jsx9(
|
|
1948
1992
|
"div",
|
|
1949
1993
|
{
|
|
1950
1994
|
ref: stageRef,
|
|
@@ -1958,7 +2002,7 @@ function GenreTree({
|
|
|
1958
2002
|
children: svg
|
|
1959
2003
|
}
|
|
1960
2004
|
),
|
|
1961
|
-
panel && /* @__PURE__ */
|
|
2005
|
+
panel && /* @__PURE__ */ jsx9(
|
|
1962
2006
|
InfoPanel,
|
|
1963
2007
|
{
|
|
1964
2008
|
node: panel.node,
|
|
@@ -2008,10 +2052,6 @@ function GenreTree({
|
|
|
2008
2052
|
hideTitle: hideInfoPanelTitle,
|
|
2009
2053
|
itemCountLabel,
|
|
2010
2054
|
readOnly,
|
|
2011
|
-
editMode,
|
|
2012
|
-
onEditModeChange,
|
|
2013
|
-
renderTitleEditor,
|
|
2014
|
-
renderParentsEditor,
|
|
2015
2055
|
renderDangerZone,
|
|
2016
2056
|
expanded,
|
|
2017
2057
|
onExpandedChange,
|
|
@@ -2030,54 +2070,15 @@ function GenreTree({
|
|
|
2030
2070
|
} : void 0
|
|
2031
2071
|
}
|
|
2032
2072
|
),
|
|
2033
|
-
overlayPanel && /* @__PURE__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2035
|
-
|
|
2073
|
+
overlayPanel && /* @__PURE__ */ jsx9(OverlayPanel, { ...overlayPanel }),
|
|
2074
|
+
/* @__PURE__ */ jsx9(
|
|
2075
|
+
FloatingControls,
|
|
2036
2076
|
{
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
/* @__PURE__ */ jsx7(
|
|
2043
|
-
"button",
|
|
2044
|
-
{
|
|
2045
|
-
type: "button",
|
|
2046
|
-
className: [
|
|
2047
|
-
"gtv-zoom-btn",
|
|
2048
|
-
!panZoom.canZoomIn && "gtv-zoom-btn--disabled"
|
|
2049
|
-
].filter(Boolean).join(" "),
|
|
2050
|
-
disabled: !panZoom.canZoomIn,
|
|
2051
|
-
onClick: panZoom.zoomIn,
|
|
2052
|
-
"aria-label": "Zoom in",
|
|
2053
|
-
children: /* @__PURE__ */ jsx7(MdZoomIn2, { className: "gtv-icon", size: 18 })
|
|
2054
|
-
}
|
|
2055
|
-
),
|
|
2056
|
-
/* @__PURE__ */ jsx7(
|
|
2057
|
-
"button",
|
|
2058
|
-
{
|
|
2059
|
-
type: "button",
|
|
2060
|
-
className: [
|
|
2061
|
-
"gtv-zoom-btn",
|
|
2062
|
-
!panZoom.canZoomOut && "gtv-zoom-btn--disabled"
|
|
2063
|
-
].filter(Boolean).join(" "),
|
|
2064
|
-
disabled: !panZoom.canZoomOut,
|
|
2065
|
-
onClick: panZoom.zoomOut,
|
|
2066
|
-
"aria-label": "Zoom out",
|
|
2067
|
-
children: /* @__PURE__ */ jsx7(MdZoomOut, { className: "gtv-icon", size: 18 })
|
|
2068
|
-
}
|
|
2069
|
-
),
|
|
2070
|
-
/* @__PURE__ */ jsx7(
|
|
2071
|
-
"button",
|
|
2072
|
-
{
|
|
2073
|
-
type: "button",
|
|
2074
|
-
className: "gtv-zoom-btn",
|
|
2075
|
-
onClick: () => panZoom.fitToFrame(queryTreeContentElements(svgRef.current)),
|
|
2076
|
-
"aria-label": "Fit to frame",
|
|
2077
|
-
children: /* @__PURE__ */ jsx7(MdFitScreen, { className: "gtv-icon", size: 18 })
|
|
2078
|
-
}
|
|
2079
|
-
)
|
|
2080
|
-
] })
|
|
2077
|
+
panZoom,
|
|
2078
|
+
orientation: controlsOrientation,
|
|
2079
|
+
leading: floatingControlsLeading,
|
|
2080
|
+
busy,
|
|
2081
|
+
onFit: () => panZoom.fitToFrame(queryTreeContentElements(svgRef.current))
|
|
2081
2082
|
}
|
|
2082
2083
|
)
|
|
2083
2084
|
]
|
|
@@ -2087,7 +2088,6 @@ function GenreTree({
|
|
|
2087
2088
|
|
|
2088
2089
|
// src/GenreTreeWheelBase.tsx
|
|
2089
2090
|
import { useEffect as useEffect6, useMemo as useMemo3, useRef as useRef6, useState as useState5 } from "react";
|
|
2090
|
-
import { MdFitScreen as MdFitScreen2, MdZoomIn as MdZoomIn3, MdZoomOut as MdZoomOut2 } from "react-icons/md";
|
|
2091
2091
|
import * as d32 from "d3";
|
|
2092
2092
|
|
|
2093
2093
|
// src/root-grouping.ts
|
|
@@ -2163,7 +2163,7 @@ function computeRotationForSelection(currentRotationDeg, targetAngle, landingAng
|
|
|
2163
2163
|
}
|
|
2164
2164
|
|
|
2165
2165
|
// src/GenreTreeWheelBase.tsx
|
|
2166
|
-
import { jsx as
|
|
2166
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2167
2167
|
function WheelCore({
|
|
2168
2168
|
nodes,
|
|
2169
2169
|
className,
|
|
@@ -2189,10 +2189,6 @@ function WheelCore({
|
|
|
2189
2189
|
hideInfoPanelTitle = false,
|
|
2190
2190
|
itemCountLabel,
|
|
2191
2191
|
readOnly,
|
|
2192
|
-
editMode,
|
|
2193
|
-
onEditModeChange,
|
|
2194
|
-
renderTitleEditor,
|
|
2195
|
-
renderParentsEditor,
|
|
2196
2192
|
renderDangerZone,
|
|
2197
2193
|
expanded,
|
|
2198
2194
|
onExpandedChange,
|
|
@@ -2203,6 +2199,8 @@ function WheelCore({
|
|
|
2203
2199
|
defaultViewport,
|
|
2204
2200
|
onViewportChange,
|
|
2205
2201
|
controlsOrientation = "vertical",
|
|
2202
|
+
floatingControlsLeading,
|
|
2203
|
+
busy,
|
|
2206
2204
|
selectedNodeId
|
|
2207
2205
|
}) {
|
|
2208
2206
|
const treeOrientation = direction === "left" ? "horizontal-anchored" : "vertical";
|
|
@@ -2318,10 +2316,11 @@ function WheelCore({
|
|
|
2318
2316
|
);
|
|
2319
2317
|
showNodeInfo(targetNode, element, viewportRef.current, { notify: false });
|
|
2320
2318
|
}, [selectedNodeId, effectiveRootId, nodes, panel, showNodeInfo]);
|
|
2321
|
-
return /* @__PURE__ */
|
|
2319
|
+
return /* @__PURE__ */ jsxs9(
|
|
2322
2320
|
"div",
|
|
2323
2321
|
{
|
|
2324
2322
|
ref: viewportRef,
|
|
2323
|
+
"aria-busy": busy,
|
|
2325
2324
|
className: [
|
|
2326
2325
|
"gtv-wheel-container",
|
|
2327
2326
|
direction === "left" && "gtv-wheel-container--left",
|
|
@@ -2336,7 +2335,7 @@ function WheelCore({
|
|
|
2336
2335
|
},
|
|
2337
2336
|
onPointerDown: panZoom.handlePointerDown,
|
|
2338
2337
|
children: [
|
|
2339
|
-
/* @__PURE__ */
|
|
2338
|
+
/* @__PURE__ */ jsx10(
|
|
2340
2339
|
"div",
|
|
2341
2340
|
{
|
|
2342
2341
|
ref: stageRef,
|
|
@@ -2349,7 +2348,7 @@ function WheelCore({
|
|
|
2349
2348
|
transform: panZoom.transform,
|
|
2350
2349
|
transformOrigin: "0 0"
|
|
2351
2350
|
},
|
|
2352
|
-
children: /* @__PURE__ */
|
|
2351
|
+
children: /* @__PURE__ */ jsxs9(
|
|
2353
2352
|
"div",
|
|
2354
2353
|
{
|
|
2355
2354
|
className: "gtv-wheel-stage",
|
|
@@ -2357,7 +2356,7 @@ function WheelCore({
|
|
|
2357
2356
|
[chipHalfExtentVar]: `${rootChipHalfExtent}px`
|
|
2358
2357
|
},
|
|
2359
2358
|
children: [
|
|
2360
|
-
selectedGroup && /* @__PURE__ */
|
|
2359
|
+
selectedGroup && /* @__PURE__ */ jsx10("div", { className: "gtv-wheel-tree-anchor", ref: treeAnchorRef, children: /* @__PURE__ */ jsx10(
|
|
2361
2360
|
GenreTree,
|
|
2362
2361
|
{
|
|
2363
2362
|
nodes: selectedGroup.nodes,
|
|
@@ -2395,9 +2394,9 @@ function WheelCore({
|
|
|
2395
2394
|
},
|
|
2396
2395
|
selectedGroup.root.id
|
|
2397
2396
|
) }),
|
|
2398
|
-
/* @__PURE__ */
|
|
2399
|
-
centerLabel && /* @__PURE__ */
|
|
2400
|
-
/* @__PURE__ */
|
|
2397
|
+
/* @__PURE__ */ jsx10("div", { className: "gtv-wheel-circle", ref: wheelCircleRef }),
|
|
2398
|
+
centerLabel && /* @__PURE__ */ jsx10("div", { className: "gtv-wheel-center-label", children: centerLabel }),
|
|
2399
|
+
/* @__PURE__ */ jsxs9(
|
|
2401
2400
|
"div",
|
|
2402
2401
|
{
|
|
2403
2402
|
className: "gtv-wheel",
|
|
@@ -2405,7 +2404,7 @@ function WheelCore({
|
|
|
2405
2404
|
"--gtv-wheel-rotation": `${rotationDeg}deg`
|
|
2406
2405
|
},
|
|
2407
2406
|
children: [
|
|
2408
|
-
sectorFillGradient && /* @__PURE__ */
|
|
2407
|
+
sectorFillGradient && /* @__PURE__ */ jsx10(
|
|
2409
2408
|
"div",
|
|
2410
2409
|
{
|
|
2411
2410
|
className: "gtv-wheel-sector-fill",
|
|
@@ -2414,7 +2413,7 @@ function WheelCore({
|
|
|
2414
2413
|
}
|
|
2415
2414
|
}
|
|
2416
2415
|
),
|
|
2417
|
-
groups.length > 1 && groups.map((group, index) => /* @__PURE__ */
|
|
2416
|
+
groups.length > 1 && groups.map((group, index) => /* @__PURE__ */ jsx10(
|
|
2418
2417
|
"div",
|
|
2419
2418
|
{
|
|
2420
2419
|
className: "gtv-wheel-divider",
|
|
@@ -2437,12 +2436,12 @@ function WheelCore({
|
|
|
2437
2436
|
rootItemCount,
|
|
2438
2437
|
rootItemCountRange
|
|
2439
2438
|
);
|
|
2440
|
-
return /* @__PURE__ */
|
|
2439
|
+
return /* @__PURE__ */ jsx10(
|
|
2441
2440
|
"div",
|
|
2442
2441
|
{
|
|
2443
2442
|
className: "gtv-wheel-slot",
|
|
2444
2443
|
style: { "--gtv-chip-angle": `${angle}deg` },
|
|
2445
|
-
children: /* @__PURE__ */
|
|
2444
|
+
children: /* @__PURE__ */ jsx10("div", { className: "gtv-wheel-chip-anchor", children: /* @__PURE__ */ jsxs9(
|
|
2446
2445
|
"button",
|
|
2447
2446
|
{
|
|
2448
2447
|
type: "button",
|
|
@@ -2478,8 +2477,8 @@ function WheelCore({
|
|
|
2478
2477
|
}
|
|
2479
2478
|
},
|
|
2480
2479
|
children: [
|
|
2481
|
-
PER_TREE_ACCENT_DOT && /* @__PURE__ */
|
|
2482
|
-
/* @__PURE__ */
|
|
2480
|
+
PER_TREE_ACCENT_DOT && /* @__PURE__ */ jsx10("span", { className: "gtv-wheel-chip-dot" }),
|
|
2481
|
+
/* @__PURE__ */ jsx10(
|
|
2483
2482
|
"span",
|
|
2484
2483
|
{
|
|
2485
2484
|
className: "gtv-node-label gtv-node-label--root",
|
|
@@ -2502,7 +2501,7 @@ function WheelCore({
|
|
|
2502
2501
|
)
|
|
2503
2502
|
}
|
|
2504
2503
|
),
|
|
2505
|
-
panel && /* @__PURE__ */
|
|
2504
|
+
panel && /* @__PURE__ */ jsx10(
|
|
2506
2505
|
InfoPanel,
|
|
2507
2506
|
{
|
|
2508
2507
|
node: panel.node,
|
|
@@ -2549,10 +2548,6 @@ function WheelCore({
|
|
|
2549
2548
|
hideTitle: hideInfoPanelTitle,
|
|
2550
2549
|
itemCountLabel,
|
|
2551
2550
|
readOnly,
|
|
2552
|
-
editMode,
|
|
2553
|
-
onEditModeChange,
|
|
2554
|
-
renderTitleEditor,
|
|
2555
|
-
renderParentsEditor,
|
|
2556
2551
|
renderDangerZone,
|
|
2557
2552
|
expanded,
|
|
2558
2553
|
onExpandedChange,
|
|
@@ -2571,57 +2566,18 @@ function WheelCore({
|
|
|
2571
2566
|
} : void 0
|
|
2572
2567
|
}
|
|
2573
2568
|
),
|
|
2574
|
-
overlayPanel && /* @__PURE__ */
|
|
2575
|
-
/* @__PURE__ */
|
|
2576
|
-
|
|
2569
|
+
overlayPanel && /* @__PURE__ */ jsx10(OverlayPanel, { ...overlayPanel }),
|
|
2570
|
+
/* @__PURE__ */ jsx10(
|
|
2571
|
+
FloatingControls,
|
|
2577
2572
|
{
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
type: "button",
|
|
2587
|
-
className: [
|
|
2588
|
-
"gtv-zoom-btn",
|
|
2589
|
-
!panZoom.canZoomIn && "gtv-zoom-btn--disabled"
|
|
2590
|
-
].filter(Boolean).join(" "),
|
|
2591
|
-
disabled: !panZoom.canZoomIn,
|
|
2592
|
-
onClick: panZoom.zoomIn,
|
|
2593
|
-
"aria-label": "Zoom in",
|
|
2594
|
-
children: /* @__PURE__ */ jsx8(MdZoomIn3, { className: "gtv-icon", size: 18 })
|
|
2595
|
-
}
|
|
2596
|
-
),
|
|
2597
|
-
/* @__PURE__ */ jsx8(
|
|
2598
|
-
"button",
|
|
2599
|
-
{
|
|
2600
|
-
type: "button",
|
|
2601
|
-
className: [
|
|
2602
|
-
"gtv-zoom-btn",
|
|
2603
|
-
!panZoom.canZoomOut && "gtv-zoom-btn--disabled"
|
|
2604
|
-
].filter(Boolean).join(" "),
|
|
2605
|
-
disabled: !panZoom.canZoomOut,
|
|
2606
|
-
onClick: panZoom.zoomOut,
|
|
2607
|
-
"aria-label": "Zoom out",
|
|
2608
|
-
children: /* @__PURE__ */ jsx8(MdZoomOut2, { className: "gtv-icon", size: 18 })
|
|
2609
|
-
}
|
|
2610
|
-
),
|
|
2611
|
-
/* @__PURE__ */ jsx8(
|
|
2612
|
-
"button",
|
|
2613
|
-
{
|
|
2614
|
-
type: "button",
|
|
2615
|
-
className: "gtv-zoom-btn",
|
|
2616
|
-
onClick: () => panZoom.fitToFrame([
|
|
2617
|
-
wheelCircleRef.current,
|
|
2618
|
-
...queryTreeContentElements(treeAnchorRef.current)
|
|
2619
|
-
]),
|
|
2620
|
-
"aria-label": "Fit to frame",
|
|
2621
|
-
children: /* @__PURE__ */ jsx8(MdFitScreen2, { className: "gtv-icon", size: 18 })
|
|
2622
|
-
}
|
|
2623
|
-
)
|
|
2624
|
-
] })
|
|
2573
|
+
panZoom,
|
|
2574
|
+
orientation: controlsOrientation,
|
|
2575
|
+
leading: floatingControlsLeading,
|
|
2576
|
+
busy,
|
|
2577
|
+
onFit: () => panZoom.fitToFrame([
|
|
2578
|
+
wheelCircleRef.current,
|
|
2579
|
+
...queryTreeContentElements(treeAnchorRef.current)
|
|
2580
|
+
])
|
|
2625
2581
|
}
|
|
2626
2582
|
)
|
|
2627
2583
|
]
|
|
@@ -2630,20 +2586,19 @@ function WheelCore({
|
|
|
2630
2586
|
}
|
|
2631
2587
|
|
|
2632
2588
|
// src/GenreTreeWheel.tsx
|
|
2633
|
-
import { jsx as
|
|
2589
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2634
2590
|
function GenreTreeWheel(props) {
|
|
2635
|
-
return /* @__PURE__ */
|
|
2591
|
+
return /* @__PURE__ */ jsx11(WheelCore, { ...props, direction: "bottom" });
|
|
2636
2592
|
}
|
|
2637
2593
|
|
|
2638
2594
|
// src/GenreTreeWheelRight.tsx
|
|
2639
|
-
import { jsx as
|
|
2595
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
2640
2596
|
function GenreTreeWheelRight(props) {
|
|
2641
|
-
return /* @__PURE__ */
|
|
2597
|
+
return /* @__PURE__ */ jsx12(WheelCore, { ...props, direction: "left" });
|
|
2642
2598
|
}
|
|
2643
2599
|
|
|
2644
2600
|
// src/GenreTreeWheelRadialBase.tsx
|
|
2645
2601
|
import { useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo4, useRef as useRef7, useState as useState6 } from "react";
|
|
2646
|
-
import { MdFitScreen as MdFitScreen3, MdZoomIn as MdZoomIn4, MdZoomOut as MdZoomOut3 } from "react-icons/md";
|
|
2647
2602
|
import * as d33 from "d3";
|
|
2648
2603
|
|
|
2649
2604
|
// src/defer-click.ts
|
|
@@ -2827,6 +2782,7 @@ function pickEmptyLabelSpot(area, width, height, obstacles, prefer = () => true)
|
|
|
2827
2782
|
var POP_WEDGE_SPAN_DEGREES = 80;
|
|
2828
2783
|
var POP_SUBTREE_OUTER_MARGIN = 24;
|
|
2829
2784
|
var POP_HIERARCHY_ROOT_ABSOLUTE_DEPTH = 1;
|
|
2785
|
+
var DOT_RADIUS_TRANSITION_MS = 250;
|
|
2830
2786
|
function getRadialDepthRadius(depth, coreRootCircleRadius, depthSpacing) {
|
|
2831
2787
|
return coreRootCircleRadius + depth * depthSpacing;
|
|
2832
2788
|
}
|
|
@@ -2849,14 +2805,13 @@ function calculatePopSubtreeRadialExtent(hierarchy, coreRootCircleRadius = 0) {
|
|
|
2849
2805
|
POP_TREE_DEPTH_RADIAL_SPACING
|
|
2850
2806
|
) + MAX_NODE_WIDTH / 2 + POP_SUBTREE_OUTER_MARGIN;
|
|
2851
2807
|
}
|
|
2852
|
-
function computePopRadialLayout(d3Lib, hierarchy, wedgeCenterAngleDegrees, coreRootCircleRadius, wedgeSpanDegrees = POP_WEDGE_SPAN_DEGREES, depthSpacing = POP_TREE_DEPTH_RADIAL_SPACING
|
|
2808
|
+
function computePopRadialLayout(d3Lib, hierarchy, wedgeCenterAngleDegrees, coreRootCircleRadius, wedgeSpanDegrees = POP_WEDGE_SPAN_DEGREES, depthSpacing = POP_TREE_DEPTH_RADIAL_SPACING) {
|
|
2853
2809
|
return layoutWedge(
|
|
2854
2810
|
d3Lib,
|
|
2855
2811
|
hierarchy,
|
|
2856
2812
|
wedgeCenterAngleDegrees,
|
|
2857
2813
|
wedgeSpanDegrees,
|
|
2858
|
-
popRadiusOfDepth(coreRootCircleRadius, depthSpacing)
|
|
2859
|
-
itemCountRange
|
|
2814
|
+
popRadiusOfDepth(coreRootCircleRadius, depthSpacing)
|
|
2860
2815
|
);
|
|
2861
2816
|
}
|
|
2862
2817
|
var MIN_DOT_GAP = 5.6;
|
|
@@ -2866,15 +2821,15 @@ function popRadiusOfDepth(coreRootCircleRadius, depthSpacing) {
|
|
|
2866
2821
|
function coreRadiusOfDepth(coreRootCircleRadius, depthSpacing) {
|
|
2867
2822
|
return (depth) => getRadialDepthRadius(depth + 1, coreRootCircleRadius, depthSpacing);
|
|
2868
2823
|
}
|
|
2869
|
-
function measureWedge(_d3Lib, hierarchy, radiusOfDepth
|
|
2870
|
-
const dotRadius = (
|
|
2824
|
+
function measureWedge(_d3Lib, hierarchy, radiusOfDepth) {
|
|
2825
|
+
const dotRadius = () => NODE_LAYOUT_SLOT_RADIUS;
|
|
2871
2826
|
const offsetFromParent = /* @__PURE__ */ new Map();
|
|
2872
2827
|
const shiftLevel = (level, by) => ({
|
|
2873
2828
|
left: { ...level.left, x: level.left.x + by },
|
|
2874
2829
|
right: { ...level.right, x: level.right.x + by }
|
|
2875
2830
|
});
|
|
2876
2831
|
const pack = (node) => {
|
|
2877
|
-
const own = { x: 0, dotRadius: dotRadius(
|
|
2832
|
+
const own = { x: 0, dotRadius: dotRadius() };
|
|
2878
2833
|
if (!node.children) return [{ left: own, right: own }];
|
|
2879
2834
|
const below = [];
|
|
2880
2835
|
const childOffsets = [];
|
|
@@ -2906,7 +2861,7 @@ function measureWedge(_d3Lib, hierarchy, radiusOfDepth, itemCountRange) {
|
|
|
2906
2861
|
let min = Infinity;
|
|
2907
2862
|
let max = -Infinity;
|
|
2908
2863
|
hierarchy.each((d) => {
|
|
2909
|
-
const inset = (dotRadius(
|
|
2864
|
+
const inset = (dotRadius() + MIN_DOT_GAP / 2) / radiusOfDepth(d.depth);
|
|
2910
2865
|
min = Math.min(min, d.x - inset);
|
|
2911
2866
|
max = Math.max(max, d.x + inset);
|
|
2912
2867
|
});
|
|
@@ -2916,13 +2871,44 @@ function measureWedge(_d3Lib, hierarchy, radiusOfDepth, itemCountRange) {
|
|
|
2916
2871
|
return max - min;
|
|
2917
2872
|
}
|
|
2918
2873
|
var MAX_WEDGE_STRETCH = 1.42;
|
|
2919
|
-
function
|
|
2920
|
-
|
|
2874
|
+
function splitAtBranching(hierarchy) {
|
|
2875
|
+
let branching = hierarchy;
|
|
2876
|
+
const chain = [];
|
|
2877
|
+
while (branching.children?.length === 1) {
|
|
2878
|
+
chain.push(branching);
|
|
2879
|
+
branching = branching.children[0];
|
|
2880
|
+
}
|
|
2881
|
+
const children = branching.children;
|
|
2882
|
+
return children && children.length > 1 ? { chain, branching, children } : null;
|
|
2883
|
+
}
|
|
2884
|
+
function layoutWedge(d3Lib, hierarchy, wedgeCenterAngleDegrees, wedgeSpanDegrees, radiusOfDepth, slack = "center") {
|
|
2885
|
+
const neededRad = measureWedge(d3Lib, hierarchy, radiusOfDepth);
|
|
2921
2886
|
const wedgeSpanRad = wedgeSpanDegrees * Math.PI / 180;
|
|
2922
2887
|
const scale = Math.min(MAX_WEDGE_STRETCH, wedgeSpanRad / neededRad);
|
|
2923
|
-
const
|
|
2888
|
+
const wedgeCenterRad = wedgeCenterAngleDegrees * Math.PI / 180;
|
|
2889
|
+
const centeredStartRad = wedgeCenterRad - neededRad * scale / 2;
|
|
2890
|
+
const branchingSplit = slack === "between-children" ? splitAtBranching(hierarchy) : null;
|
|
2891
|
+
if (!branchingSplit) {
|
|
2892
|
+
hierarchy.each((d) => {
|
|
2893
|
+
const angleRad = centeredStartRad + d.x * scale;
|
|
2894
|
+
const radius = radiusOfDepth(d.depth);
|
|
2895
|
+
d.x = radius * Math.sin(angleRad);
|
|
2896
|
+
d.y = -radius * Math.cos(angleRad);
|
|
2897
|
+
});
|
|
2898
|
+
return hierarchy;
|
|
2899
|
+
}
|
|
2900
|
+
const { chain, branching, children } = branchingSplit;
|
|
2901
|
+
const gap = Math.max(0, wedgeSpanRad - neededRad * scale) / (children.length - 1);
|
|
2902
|
+
const wedgeStartRad = wedgeCenterRad - wedgeSpanRad / 2;
|
|
2903
|
+
const angleOffsetRad = /* @__PURE__ */ new Map();
|
|
2904
|
+
hierarchy.each((d) => angleOffsetRad.set(d, d.x * scale));
|
|
2905
|
+
children.forEach((child, i) => {
|
|
2906
|
+
child.each((d) => angleOffsetRad.set(d, angleOffsetRad.get(d) + i * gap));
|
|
2907
|
+
});
|
|
2908
|
+
const recenter = gap * (children.length - 1) / 2;
|
|
2909
|
+
[...chain, branching].forEach((d) => angleOffsetRad.set(d, angleOffsetRad.get(d) + recenter));
|
|
2924
2910
|
hierarchy.each((d) => {
|
|
2925
|
-
const angleRad = wedgeStartRad + d
|
|
2911
|
+
const angleRad = wedgeStartRad + angleOffsetRad.get(d);
|
|
2926
2912
|
const radius = radiusOfDepth(d.depth);
|
|
2927
2913
|
d.x = radius * Math.sin(angleRad);
|
|
2928
2914
|
d.y = -radius * Math.cos(angleRad);
|
|
@@ -3009,7 +2995,8 @@ function renderPopSubtree(d3Lib, svg, hierarchy, rootColor, reparentingNodeId, r
|
|
|
3009
2995
|
rootLinkOrigin,
|
|
3010
2996
|
isMainstreamSector = false,
|
|
3011
2997
|
selectedNodeId = null,
|
|
3012
|
-
nodeFillOf
|
|
2998
|
+
nodeFillOf,
|
|
2999
|
+
dotRadiusMemory
|
|
3013
3000
|
} = options;
|
|
3014
3001
|
const { onReparentTargetSelect, onNodeClick, onNodeDoubleClick, onNodeHover } = callbacks;
|
|
3015
3002
|
const isForbidden = (d) => reparentForbiddenIds.includes(d.data.id);
|
|
@@ -3072,13 +3059,18 @@ function renderPopSubtree(d3Lib, svg, hierarchy, rootColor, reparentingNodeId, r
|
|
|
3072
3059
|
);
|
|
3073
3060
|
d3Lib.select(this).attr("x", hitArea.x0).attr("y", hitArea.y0).attr("width", hitArea.x1 - hitArea.x0).attr("height", hitArea.y1 - hitArea.y0);
|
|
3074
3061
|
}).attr("fill", "transparent").attr("pointer-events", "all");
|
|
3075
|
-
|
|
3062
|
+
const targetDotRadius = (d) => calculateNodeDotRadius(d.data.itemCount, itemCountRange);
|
|
3063
|
+
const animateDots = dotRadiusMemory !== void 0 && !(typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches);
|
|
3064
|
+
const startDotRadius = (d) => (animateDots ? dotRadiusMemory?.get(d.data.id) : void 0) ?? targetDotRadius(d);
|
|
3065
|
+
nodes.append("circle").attr("class", "gtv-node-dot").attr("r", startDotRadius).attr("fill", nodeFill).attr(
|
|
3076
3066
|
"stroke",
|
|
3077
3067
|
(d) => isSelected(d) ? ACCENT_COLOR : isMainstreamSector ? TEXT_COLOR : SURFACE_BORDER_COLOR
|
|
3078
3068
|
).attr(
|
|
3079
3069
|
"stroke-width",
|
|
3080
3070
|
(d) => isSelected(d) ? calculateSelectedNodeBorderWidth(calculateNodeDotRadius(d.data.itemCount, itemCountRange)) : calculateNodeBorderWidth(d.data.itemCount, itemCountRange)
|
|
3081
|
-
).style("pointer-events", "none");
|
|
3071
|
+
).style("pointer-events", "none").filter((d) => startDotRadius(d) !== targetDotRadius(d)).transition().duration(DOT_RADIUS_TRANSITION_MS).ease(d3Lib.easeCubicOut).attr("r", targetDotRadius);
|
|
3072
|
+
nodes.each((d) => dotRadiusMemory?.set(d.data.id, targetDotRadius(d)));
|
|
3073
|
+
nodes.sort((a, b) => targetDotRadius(b) - targetDotRadius(a));
|
|
3082
3074
|
nodes.append("text").attr(
|
|
3083
3075
|
"class",
|
|
3084
3076
|
"gtv-node-label"
|
|
@@ -3201,14 +3193,14 @@ function buildCoreHierarchy(d3Lib, coreNodes) {
|
|
|
3201
3193
|
});
|
|
3202
3194
|
return hierarchy;
|
|
3203
3195
|
}
|
|
3204
|
-
function computeCoreRadialLayout(d3Lib, hierarchy, wedgeCenterAngleDegrees, wedgeSpanDegrees, coreRootCircleRadius, depthSpacing
|
|
3196
|
+
function computeCoreRadialLayout(d3Lib, hierarchy, wedgeCenterAngleDegrees, wedgeSpanDegrees, coreRootCircleRadius, depthSpacing) {
|
|
3205
3197
|
return layoutWedge(
|
|
3206
3198
|
d3Lib,
|
|
3207
3199
|
hierarchy,
|
|
3208
3200
|
wedgeCenterAngleDegrees,
|
|
3209
3201
|
wedgeSpanDegrees,
|
|
3210
3202
|
coreRadiusOfDepth(coreRootCircleRadius, depthSpacing),
|
|
3211
|
-
|
|
3203
|
+
"between-children"
|
|
3212
3204
|
);
|
|
3213
3205
|
}
|
|
3214
3206
|
function calculateCoreSubtreeRadialExtent(hierarchy, depthSpacing, coreRootCircleRadius = 0) {
|
|
@@ -3248,7 +3240,7 @@ function splitRootGroupBySide(group) {
|
|
|
3248
3240
|
}
|
|
3249
3241
|
|
|
3250
3242
|
// src/GenreTreeWheelRadialBase.tsx
|
|
3251
|
-
import { jsx as
|
|
3243
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3252
3244
|
var LANDING_ANGLE = 90;
|
|
3253
3245
|
function computeContinuousAngles(groups, layout, previous) {
|
|
3254
3246
|
const angles = /* @__PURE__ */ new Map();
|
|
@@ -3283,10 +3275,6 @@ function WheelRadialCore({
|
|
|
3283
3275
|
hideInfoPanelTitle = false,
|
|
3284
3276
|
itemCountLabel,
|
|
3285
3277
|
readOnly,
|
|
3286
|
-
editMode,
|
|
3287
|
-
onEditModeChange,
|
|
3288
|
-
renderTitleEditor,
|
|
3289
|
-
renderParentsEditor,
|
|
3290
3278
|
renderDangerZone,
|
|
3291
3279
|
expanded,
|
|
3292
3280
|
onExpandedChange,
|
|
@@ -3297,6 +3285,8 @@ function WheelRadialCore({
|
|
|
3297
3285
|
defaultViewport,
|
|
3298
3286
|
onViewportChange,
|
|
3299
3287
|
controlsOrientation = "vertical",
|
|
3288
|
+
floatingControlsLeading,
|
|
3289
|
+
busy,
|
|
3300
3290
|
selectedNodeId
|
|
3301
3291
|
}) {
|
|
3302
3292
|
const index = useTreeIndex(nodes);
|
|
@@ -3455,8 +3445,7 @@ function WheelRadialCore({
|
|
|
3455
3445
|
angle,
|
|
3456
3446
|
span,
|
|
3457
3447
|
wheelRadius,
|
|
3458
|
-
POP_TREE_DEPTH_RADIAL_SPACING
|
|
3459
|
-
wheelItemCountRange
|
|
3448
|
+
POP_TREE_DEPTH_RADIAL_SPACING
|
|
3460
3449
|
);
|
|
3461
3450
|
const reparentForbiddenIds = reparentingNodeId ? laidOut.descendants().find((d) => d.data.id === reparentingNodeId)?.descendants().map((d) => d.data.id) ?? [] : [];
|
|
3462
3451
|
const branchGroup = sectorGroup.append("g").attr("class", "gtv-wheel-core-branch").attr("data-gtv-branch-index", branchIndex);
|
|
@@ -3572,10 +3561,11 @@ function WheelRadialCore({
|
|
|
3572
3561
|
};
|
|
3573
3562
|
});
|
|
3574
3563
|
}, [groups, continuousAngleByRootId, sectorSpanByRootId]);
|
|
3575
|
-
return /* @__PURE__ */
|
|
3564
|
+
return /* @__PURE__ */ jsxs10(
|
|
3576
3565
|
"div",
|
|
3577
3566
|
{
|
|
3578
3567
|
ref: viewportRef,
|
|
3568
|
+
"aria-busy": busy,
|
|
3579
3569
|
className: [
|
|
3580
3570
|
"gtv-wheel-container",
|
|
3581
3571
|
"gtv-wheel-container--radial",
|
|
@@ -3589,7 +3579,7 @@ function WheelRadialCore({
|
|
|
3589
3579
|
},
|
|
3590
3580
|
onPointerDown: panZoom.handlePointerDown,
|
|
3591
3581
|
children: [
|
|
3592
|
-
/* @__PURE__ */
|
|
3582
|
+
/* @__PURE__ */ jsx13(
|
|
3593
3583
|
"div",
|
|
3594
3584
|
{
|
|
3595
3585
|
ref: stageRef,
|
|
@@ -3602,9 +3592,9 @@ function WheelRadialCore({
|
|
|
3602
3592
|
transform: panZoom.transform,
|
|
3603
3593
|
transformOrigin: "0 0"
|
|
3604
3594
|
},
|
|
3605
|
-
children: /* @__PURE__ */
|
|
3606
|
-
/* @__PURE__ */
|
|
3607
|
-
/* @__PURE__ */
|
|
3595
|
+
children: /* @__PURE__ */ jsxs10("div", { className: "gtv-wheel-stage", children: [
|
|
3596
|
+
/* @__PURE__ */ jsx13("div", { className: "gtv-wheel-circle", ref: wheelCircleRef }),
|
|
3597
|
+
/* @__PURE__ */ jsx13("div", { className: "gtv-wheel", children: sectorFills.map((sector) => /* @__PURE__ */ jsx13(
|
|
3608
3598
|
"div",
|
|
3609
3599
|
{
|
|
3610
3600
|
className: "gtv-wheel-sector",
|
|
@@ -3616,7 +3606,7 @@ function WheelRadialCore({
|
|
|
3616
3606
|
},
|
|
3617
3607
|
`sector-${sector.rootId}`
|
|
3618
3608
|
)) }),
|
|
3619
|
-
/* @__PURE__ */
|
|
3609
|
+
/* @__PURE__ */ jsx13(
|
|
3620
3610
|
"svg",
|
|
3621
3611
|
{
|
|
3622
3612
|
ref: coreSvgRef,
|
|
@@ -3625,9 +3615,9 @@ function WheelRadialCore({
|
|
|
3625
3615
|
height: wheelRadius * 2
|
|
3626
3616
|
}
|
|
3627
3617
|
),
|
|
3628
|
-
centerLabel && /* @__PURE__ */
|
|
3629
|
-
/* @__PURE__ */
|
|
3630
|
-
dividerAngles.map((angle, index2) => /* @__PURE__ */
|
|
3618
|
+
centerLabel && /* @__PURE__ */ jsx13("div", { className: "gtv-wheel-center-label", children: centerLabel }),
|
|
3619
|
+
/* @__PURE__ */ jsxs10("div", { className: "gtv-wheel", children: [
|
|
3620
|
+
dividerAngles.map((angle, index2) => /* @__PURE__ */ jsx13(
|
|
3631
3621
|
"div",
|
|
3632
3622
|
{
|
|
3633
3623
|
className: "gtv-wheel-divider",
|
|
@@ -3650,12 +3640,12 @@ function WheelRadialCore({
|
|
|
3650
3640
|
rootItemCount,
|
|
3651
3641
|
rootItemCountRange
|
|
3652
3642
|
);
|
|
3653
|
-
return /* @__PURE__ */
|
|
3643
|
+
return /* @__PURE__ */ jsx13(
|
|
3654
3644
|
"div",
|
|
3655
3645
|
{
|
|
3656
3646
|
className: "gtv-wheel-slot",
|
|
3657
3647
|
style: { "--gtv-chip-angle": `${angle}deg` },
|
|
3658
|
-
children: /* @__PURE__ */
|
|
3648
|
+
children: /* @__PURE__ */ jsx13("div", { className: "gtv-wheel-chip-anchor", children: /* @__PURE__ */ jsxs10(
|
|
3659
3649
|
"button",
|
|
3660
3650
|
{
|
|
3661
3651
|
type: "button",
|
|
@@ -3688,8 +3678,8 @@ function WheelRadialCore({
|
|
|
3688
3678
|
}
|
|
3689
3679
|
},
|
|
3690
3680
|
children: [
|
|
3691
|
-
PER_TREE_ACCENT_DOT && /* @__PURE__ */
|
|
3692
|
-
/* @__PURE__ */
|
|
3681
|
+
PER_TREE_ACCENT_DOT && /* @__PURE__ */ jsx13("span", { className: "gtv-wheel-chip-dot" }),
|
|
3682
|
+
/* @__PURE__ */ jsx13(
|
|
3693
3683
|
"span",
|
|
3694
3684
|
{
|
|
3695
3685
|
className: "gtv-node-label gtv-node-label--root",
|
|
@@ -3708,7 +3698,7 @@ function WheelRadialCore({
|
|
|
3708
3698
|
] })
|
|
3709
3699
|
}
|
|
3710
3700
|
),
|
|
3711
|
-
panel && /* @__PURE__ */
|
|
3701
|
+
panel && /* @__PURE__ */ jsx13(
|
|
3712
3702
|
InfoPanel,
|
|
3713
3703
|
{
|
|
3714
3704
|
node: panel.node,
|
|
@@ -3754,10 +3744,6 @@ function WheelRadialCore({
|
|
|
3754
3744
|
hideTitle: hideInfoPanelTitle,
|
|
3755
3745
|
itemCountLabel,
|
|
3756
3746
|
readOnly,
|
|
3757
|
-
editMode,
|
|
3758
|
-
onEditModeChange,
|
|
3759
|
-
renderTitleEditor,
|
|
3760
|
-
renderParentsEditor,
|
|
3761
3747
|
renderDangerZone,
|
|
3762
3748
|
expanded,
|
|
3763
3749
|
onExpandedChange,
|
|
@@ -3776,54 +3762,15 @@ function WheelRadialCore({
|
|
|
3776
3762
|
} : void 0
|
|
3777
3763
|
}
|
|
3778
3764
|
),
|
|
3779
|
-
overlayPanel && /* @__PURE__ */
|
|
3780
|
-
/* @__PURE__ */
|
|
3781
|
-
|
|
3765
|
+
overlayPanel && /* @__PURE__ */ jsx13(OverlayPanel, { ...overlayPanel }),
|
|
3766
|
+
/* @__PURE__ */ jsx13(
|
|
3767
|
+
FloatingControls,
|
|
3782
3768
|
{
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
/* @__PURE__ */ jsx11(
|
|
3789
|
-
"button",
|
|
3790
|
-
{
|
|
3791
|
-
type: "button",
|
|
3792
|
-
className: [
|
|
3793
|
-
"gtv-zoom-btn",
|
|
3794
|
-
!panZoom.canZoomIn && "gtv-zoom-btn--disabled"
|
|
3795
|
-
].filter(Boolean).join(" "),
|
|
3796
|
-
disabled: !panZoom.canZoomIn,
|
|
3797
|
-
onClick: panZoom.zoomIn,
|
|
3798
|
-
"aria-label": "Zoom in",
|
|
3799
|
-
children: /* @__PURE__ */ jsx11(MdZoomIn4, { className: "gtv-icon", size: 18 })
|
|
3800
|
-
}
|
|
3801
|
-
),
|
|
3802
|
-
/* @__PURE__ */ jsx11(
|
|
3803
|
-
"button",
|
|
3804
|
-
{
|
|
3805
|
-
type: "button",
|
|
3806
|
-
className: [
|
|
3807
|
-
"gtv-zoom-btn",
|
|
3808
|
-
!panZoom.canZoomOut && "gtv-zoom-btn--disabled"
|
|
3809
|
-
].filter(Boolean).join(" "),
|
|
3810
|
-
disabled: !panZoom.canZoomOut,
|
|
3811
|
-
onClick: panZoom.zoomOut,
|
|
3812
|
-
"aria-label": "Zoom out",
|
|
3813
|
-
children: /* @__PURE__ */ jsx11(MdZoomOut3, { className: "gtv-icon", size: 18 })
|
|
3814
|
-
}
|
|
3815
|
-
),
|
|
3816
|
-
/* @__PURE__ */ jsx11(
|
|
3817
|
-
"button",
|
|
3818
|
-
{
|
|
3819
|
-
type: "button",
|
|
3820
|
-
className: "gtv-zoom-btn",
|
|
3821
|
-
onClick: () => panZoom.fitToFrame([wheelCircleRef.current, coreSvgRef.current]),
|
|
3822
|
-
"aria-label": "Fit to frame",
|
|
3823
|
-
children: /* @__PURE__ */ jsx11(MdFitScreen3, { className: "gtv-icon", size: 18 })
|
|
3824
|
-
}
|
|
3825
|
-
)
|
|
3826
|
-
] })
|
|
3769
|
+
panZoom,
|
|
3770
|
+
orientation: controlsOrientation,
|
|
3771
|
+
leading: floatingControlsLeading,
|
|
3772
|
+
busy,
|
|
3773
|
+
onFit: () => panZoom.fitToFrame([wheelCircleRef.current, coreSvgRef.current])
|
|
3827
3774
|
}
|
|
3828
3775
|
)
|
|
3829
3776
|
]
|
|
@@ -3832,14 +3779,13 @@ function WheelRadialCore({
|
|
|
3832
3779
|
}
|
|
3833
3780
|
|
|
3834
3781
|
// src/GenreTreeWheelRadial.tsx
|
|
3835
|
-
import { jsx as
|
|
3782
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
3836
3783
|
function GenreTreeWheelRadial(props) {
|
|
3837
|
-
return /* @__PURE__ */
|
|
3784
|
+
return /* @__PURE__ */ jsx14(WheelRadialCore, { ...props });
|
|
3838
3785
|
}
|
|
3839
3786
|
|
|
3840
3787
|
// src/GenreTreeWheelRadialPopCoreBase.tsx
|
|
3841
3788
|
import { useCallback as useCallback4, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef8, useState as useState9 } from "react";
|
|
3842
|
-
import { MdFitScreen as MdFitScreen4, MdZoomIn as MdZoomIn5, MdZoomOut as MdZoomOut4 } from "react-icons/md";
|
|
3843
3789
|
import * as d34 from "d3";
|
|
3844
3790
|
|
|
3845
3791
|
// src/use-focus-history.ts
|
|
@@ -3869,16 +3815,16 @@ function useFocusHistory(focusNodeId, isFocusable) {
|
|
|
3869
3815
|
// src/WheelBreadcrumb.tsx
|
|
3870
3816
|
import { Fragment as Fragment3, useState as useState8 } from "react";
|
|
3871
3817
|
import { MdHome } from "react-icons/md";
|
|
3872
|
-
import { Fragment as Fragment4, jsx as
|
|
3818
|
+
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3873
3819
|
var MAX_VISIBLE_ANCESTORS = 3;
|
|
3874
3820
|
var ANCESTORS_KEPT_WHEN_COLLAPSED = 2;
|
|
3875
3821
|
function WheelBreadcrumb({ ancestors, currentName, onHome, onAncestor }) {
|
|
3876
3822
|
const [expanded, setExpanded] = useState8(false);
|
|
3877
3823
|
const collapsed = !expanded && ancestors.length > MAX_VISIBLE_ANCESTORS;
|
|
3878
3824
|
const visibleAncestors = collapsed ? ancestors.slice(-ANCESTORS_KEPT_WHEN_COLLAPSED) : ancestors;
|
|
3879
|
-
const separator = /* @__PURE__ */
|
|
3880
|
-
return /* @__PURE__ */
|
|
3881
|
-
/* @__PURE__ */
|
|
3825
|
+
const separator = /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u203A" });
|
|
3826
|
+
return /* @__PURE__ */ jsxs11("nav", { className: "gtv-wheel-breadcrumb", "aria-label": "Breadcrumb", children: [
|
|
3827
|
+
/* @__PURE__ */ jsx15(
|
|
3882
3828
|
"button",
|
|
3883
3829
|
{
|
|
3884
3830
|
type: "button",
|
|
@@ -3886,12 +3832,12 @@ function WheelBreadcrumb({ ancestors, currentName, onHome, onAncestor }) {
|
|
|
3886
3832
|
"aria-label": "All genres",
|
|
3887
3833
|
title: "All genres",
|
|
3888
3834
|
onClick: onHome,
|
|
3889
|
-
children: /* @__PURE__ */
|
|
3835
|
+
children: /* @__PURE__ */ jsx15(MdHome, { className: "gtv-icon", size: 14 })
|
|
3890
3836
|
}
|
|
3891
3837
|
),
|
|
3892
3838
|
separator,
|
|
3893
|
-
collapsed && /* @__PURE__ */
|
|
3894
|
-
/* @__PURE__ */
|
|
3839
|
+
collapsed && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
3840
|
+
/* @__PURE__ */ jsx15(
|
|
3895
3841
|
"button",
|
|
3896
3842
|
{
|
|
3897
3843
|
type: "button",
|
|
@@ -3904,11 +3850,11 @@ function WheelBreadcrumb({ ancestors, currentName, onHome, onAncestor }) {
|
|
|
3904
3850
|
),
|
|
3905
3851
|
separator
|
|
3906
3852
|
] }),
|
|
3907
|
-
visibleAncestors.map((ancestor) => /* @__PURE__ */
|
|
3908
|
-
/* @__PURE__ */
|
|
3853
|
+
visibleAncestors.map((ancestor) => /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
3854
|
+
/* @__PURE__ */ jsx15("button", { type: "button", className: "gtv-wheel-breadcrumb-crumb", onClick: () => onAncestor(ancestor.id), children: ancestor.name }),
|
|
3909
3855
|
separator
|
|
3910
3856
|
] }, ancestor.id)),
|
|
3911
|
-
/* @__PURE__ */
|
|
3857
|
+
/* @__PURE__ */ jsx15("span", { className: "gtv-wheel-breadcrumb-current", "aria-current": "page", children: currentName })
|
|
3912
3858
|
] });
|
|
3913
3859
|
}
|
|
3914
3860
|
|
|
@@ -3969,7 +3915,7 @@ function resolvePopCoreFrame(nodes, focusNodeId) {
|
|
|
3969
3915
|
}
|
|
3970
3916
|
|
|
3971
3917
|
// src/GenreTreeWheelRadialPopCoreBase.tsx
|
|
3972
|
-
import { jsx as
|
|
3918
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3973
3919
|
var LANDING_ANGLE2 = 90;
|
|
3974
3920
|
var CHIP_GAP = 16;
|
|
3975
3921
|
var sum = (values) => values.reduce((total, value) => total + value, 0);
|
|
@@ -4006,10 +3952,6 @@ function WheelRadialPopCoreCore({
|
|
|
4006
3952
|
hideInfoPanelTitle = false,
|
|
4007
3953
|
itemCountLabel,
|
|
4008
3954
|
readOnly,
|
|
4009
|
-
editMode,
|
|
4010
|
-
onEditModeChange,
|
|
4011
|
-
renderTitleEditor,
|
|
4012
|
-
renderParentsEditor,
|
|
4013
3955
|
renderDangerZone,
|
|
4014
3956
|
expanded,
|
|
4015
3957
|
onExpandedChange,
|
|
@@ -4020,6 +3962,8 @@ function WheelRadialPopCoreCore({
|
|
|
4020
3962
|
defaultViewport,
|
|
4021
3963
|
onViewportChange,
|
|
4022
3964
|
controlsOrientation = "vertical",
|
|
3965
|
+
floatingControlsLeading,
|
|
3966
|
+
busy,
|
|
4023
3967
|
allowWheelRotation = true,
|
|
4024
3968
|
selectedNodeId,
|
|
4025
3969
|
focusNodeId: requestedFocusNodeId = null,
|
|
@@ -4092,6 +4036,7 @@ function WheelRadialPopCoreCore({
|
|
|
4092
4036
|
}
|
|
4093
4037
|
const viewportRef = useRef8(null);
|
|
4094
4038
|
const stageRef = useRef8(null);
|
|
4039
|
+
const dotRadiusMemoryRef = useRef8(/* @__PURE__ */ new Map());
|
|
4095
4040
|
const panZoom = usePanZoom(viewportRef, wheelZoom, stageRef, { defaultViewport, onViewportChange });
|
|
4096
4041
|
const { panel: openPanel, showNodeInfo, closeNodeInfo } = useNodeInfoPanel({ selectedNodeId, onSelectedNodeChange });
|
|
4097
4042
|
const isInFrame = (id) => id === focusNodeId || centerSubtreeNodeIds.has(id) || ringRootById.has(id);
|
|
@@ -4198,8 +4143,8 @@ function WheelRadialPopCoreCore({
|
|
|
4198
4143
|
centerSubtreeHierarchy,
|
|
4199
4144
|
0,
|
|
4200
4145
|
POP_TREE_DEPTH_RADIAL_SPACING
|
|
4201
|
-
) :
|
|
4202
|
-
[centerSubtreeHierarchy
|
|
4146
|
+
) : NODE_LAYOUT_SLOT_RADIUS,
|
|
4147
|
+
[centerSubtreeHierarchy]
|
|
4203
4148
|
);
|
|
4204
4149
|
const maxCoreExtentDelta = useMemo5(() => {
|
|
4205
4150
|
let extent = 0;
|
|
@@ -4207,11 +4152,7 @@ function WheelRadialPopCoreCore({
|
|
|
4207
4152
|
core.forEach((hierarchy) => {
|
|
4208
4153
|
extent = Math.max(
|
|
4209
4154
|
extent,
|
|
4210
|
-
calculateCoreSubtreeRadialExtent(
|
|
4211
|
-
hierarchy,
|
|
4212
|
-
POP_TREE_DEPTH_RADIAL_SPACING,
|
|
4213
|
-
0
|
|
4214
|
-
)
|
|
4155
|
+
calculateCoreSubtreeRadialExtent(hierarchy, POP_TREE_DEPTH_RADIAL_SPACING, 0)
|
|
4215
4156
|
);
|
|
4216
4157
|
});
|
|
4217
4158
|
});
|
|
@@ -4225,7 +4166,7 @@ function WheelRadialPopCoreCore({
|
|
|
4225
4166
|
(radius) => new Map(
|
|
4226
4167
|
groups.map((group) => {
|
|
4227
4168
|
const { pop, core } = branchHierarchiesByRootId.get(group.root.id);
|
|
4228
|
-
const chipWidth = 2 *
|
|
4169
|
+
const chipWidth = 2 * NODE_LAYOUT_SLOT_RADIUS;
|
|
4229
4170
|
return [
|
|
4230
4171
|
group.root.id,
|
|
4231
4172
|
{
|
|
@@ -4233,16 +4174,14 @@ function WheelRadialPopCoreCore({
|
|
|
4233
4174
|
(hierarchy) => measureWedge(
|
|
4234
4175
|
d34,
|
|
4235
4176
|
hierarchy,
|
|
4236
|
-
popRadiusOfDepth(radius, POP_TREE_DEPTH_RADIAL_SPACING)
|
|
4237
|
-
wheelItemCountRange
|
|
4177
|
+
popRadiusOfDepth(radius, POP_TREE_DEPTH_RADIAL_SPACING)
|
|
4238
4178
|
)
|
|
4239
4179
|
),
|
|
4240
4180
|
core: core.map(
|
|
4241
4181
|
(hierarchy) => measureWedge(
|
|
4242
4182
|
d34,
|
|
4243
4183
|
hierarchy,
|
|
4244
|
-
coreRadiusOfDepth(radius, POP_TREE_DEPTH_RADIAL_SPACING)
|
|
4245
|
-
wheelItemCountRange
|
|
4184
|
+
coreRadiusOfDepth(radius, POP_TREE_DEPTH_RADIAL_SPACING)
|
|
4246
4185
|
)
|
|
4247
4186
|
),
|
|
4248
4187
|
chip: 2 * Math.asin(Math.min(1, (chipWidth / 2 + CHIP_GAP) / radius))
|
|
@@ -4250,7 +4189,7 @@ function WheelRadialPopCoreCore({
|
|
|
4250
4189
|
];
|
|
4251
4190
|
})
|
|
4252
4191
|
),
|
|
4253
|
-
[groups, branchHierarchiesByRootId
|
|
4192
|
+
[groups, branchHierarchiesByRootId]
|
|
4254
4193
|
);
|
|
4255
4194
|
const coreRootCircleRadius = useMemo5(
|
|
4256
4195
|
() => solveRingRadius(
|
|
@@ -4368,8 +4307,7 @@ function WheelRadialPopCoreCore({
|
|
|
4368
4307
|
angle,
|
|
4369
4308
|
coreRootCircleRadius,
|
|
4370
4309
|
span,
|
|
4371
|
-
POP_TREE_DEPTH_RADIAL_SPACING
|
|
4372
|
-
wheelItemCountRange
|
|
4310
|
+
POP_TREE_DEPTH_RADIAL_SPACING
|
|
4373
4311
|
);
|
|
4374
4312
|
const reparentForbiddenIds = reparentingNodeId ? laidOut.descendants().find((d) => d.data.id === reparentingNodeId)?.descendants().map((d) => d.data.id) ?? [] : [];
|
|
4375
4313
|
const branchGroup = sectorGroup.append("g").attr("class", "gtv-wheel-pop-branch").attr("data-gtv-branch-index", branchIndex);
|
|
@@ -4413,6 +4351,7 @@ function WheelRadialPopCoreCore({
|
|
|
4413
4351
|
{
|
|
4414
4352
|
rootLinkOrigin,
|
|
4415
4353
|
selectedNodeId: panel?.node.id ?? null,
|
|
4354
|
+
dotRadiusMemory: dotRadiusMemoryRef.current,
|
|
4416
4355
|
nodeFillOf: (node) => getGenreNodeStyle(index, node.id).fill
|
|
4417
4356
|
}
|
|
4418
4357
|
);
|
|
@@ -4425,16 +4364,42 @@ function WheelRadialPopCoreCore({
|
|
|
4425
4364
|
);
|
|
4426
4365
|
const sectorGroup = originGroup.append("g").attr("class", "gtv-wheel-core-sector").attr("data-gtv-root-id", rootId);
|
|
4427
4366
|
branches.forEach(({ hierarchy, angle, span }, branchIndex) => {
|
|
4367
|
+
const undergroundIds = new Set(
|
|
4368
|
+
hierarchy.descendants().filter((d) => d.ancestors().some((a) => a.data.scene === "underground")).map((d) => d.data.id)
|
|
4369
|
+
);
|
|
4428
4370
|
const laidOut = computeCoreRadialLayout(
|
|
4429
4371
|
d34,
|
|
4430
4372
|
hierarchy,
|
|
4431
4373
|
angle,
|
|
4432
4374
|
span,
|
|
4433
4375
|
coreRootCircleRadius,
|
|
4434
|
-
POP_TREE_DEPTH_RADIAL_SPACING
|
|
4435
|
-
wheelItemCountRange
|
|
4376
|
+
POP_TREE_DEPTH_RADIAL_SPACING
|
|
4436
4377
|
);
|
|
4437
4378
|
const reparentForbiddenIds = reparentingNodeId ? laidOut.descendants().find((d) => d.data.id === reparentingNodeId)?.descendants().map((d) => d.data.id) ?? [] : [];
|
|
4379
|
+
const angleOf = (d) => {
|
|
4380
|
+
const deg = Math.atan2(d.x, -d.y) * 180 / Math.PI;
|
|
4381
|
+
return angle + ((deg - angle + 540) % 360 + 360) % 360 - 180;
|
|
4382
|
+
};
|
|
4383
|
+
const subtreeRange = (d) => {
|
|
4384
|
+
const angles = d.descendants().map(angleOf);
|
|
4385
|
+
return { min: Math.min(...angles), max: Math.max(...angles) };
|
|
4386
|
+
};
|
|
4387
|
+
laidOut.descendants().filter((d) => d.data.scene === "underground" && !d.ancestors().slice(1).some((a) => a.data.scene === "underground")).forEach((ug) => {
|
|
4388
|
+
const mine = subtreeRange(ug);
|
|
4389
|
+
const siblings = ug.parent?.children ?? [];
|
|
4390
|
+
const at = siblings.indexOf(ug);
|
|
4391
|
+
const prev = at > 0 ? siblings[at - 1] : void 0;
|
|
4392
|
+
const next = at >= 0 ? siblings[at + 1] : void 0;
|
|
4393
|
+
const startDeg = prev ? (subtreeRange(prev).max + mine.min) / 2 : angle - span / 2;
|
|
4394
|
+
const endDeg = next ? (mine.max + subtreeRange(next).min) / 2 : angle + span / 2;
|
|
4395
|
+
const arcPath = d34.arc()({
|
|
4396
|
+
innerRadius: coreRootCircleRadius,
|
|
4397
|
+
outerRadius: SCENE_SECTOR_OUTER_RADIUS,
|
|
4398
|
+
startAngle: startDeg * Math.PI / 180,
|
|
4399
|
+
endAngle: endDeg * Math.PI / 180
|
|
4400
|
+
});
|
|
4401
|
+
sectorGroup.append("path").attr("class", "gtv-wheel-scene-sector").attr("d", arcPath).attr("fill", shadeSurface(getGenreNodeColor(index, rootId), UNDERGROUND_DARKEN_RATIO)).attr("fill-opacity", UNDERGROUND_SECTOR_FILL_OPACITY);
|
|
4402
|
+
});
|
|
4438
4403
|
const branchGroup = sectorGroup.append("g").attr("class", "gtv-wheel-core-branch").attr("data-gtv-branch-index", branchIndex);
|
|
4439
4404
|
renderPopSubtree(
|
|
4440
4405
|
d34,
|
|
@@ -4477,7 +4442,11 @@ function WheelRadialPopCoreCore({
|
|
|
4477
4442
|
isCoreSector: true,
|
|
4478
4443
|
rootLinkOrigin,
|
|
4479
4444
|
selectedNodeId: panel?.node.id ?? null,
|
|
4480
|
-
|
|
4445
|
+
dotRadiusMemory: dotRadiusMemoryRef.current,
|
|
4446
|
+
nodeFillOf: (node) => {
|
|
4447
|
+
const fill = getGenreNodeStyle(index, node.id).fill;
|
|
4448
|
+
return undergroundIds.has(node.id) ? shadeSurface(fill, UNDERGROUND_DARKEN_RATIO) : fill;
|
|
4449
|
+
}
|
|
4481
4450
|
}
|
|
4482
4451
|
);
|
|
4483
4452
|
});
|
|
@@ -4532,6 +4501,7 @@ function WheelRadialPopCoreCore({
|
|
|
4532
4501
|
skipRootNode: true,
|
|
4533
4502
|
isMainstreamSector: isCenterMainstream,
|
|
4534
4503
|
selectedNodeId: panel?.node.id ?? null,
|
|
4504
|
+
dotRadiusMemory: dotRadiusMemoryRef.current,
|
|
4535
4505
|
nodeFillOf: (node) => getGenreNodeStyle(index, node.id).fill
|
|
4536
4506
|
}
|
|
4537
4507
|
);
|
|
@@ -4727,10 +4697,11 @@ function WheelRadialPopCoreCore({
|
|
|
4727
4697
|
};
|
|
4728
4698
|
});
|
|
4729
4699
|
}, [groups, continuousAngleByRootId, sectorSpanByRootId]);
|
|
4730
|
-
return /* @__PURE__ */
|
|
4700
|
+
return /* @__PURE__ */ jsxs12(
|
|
4731
4701
|
"div",
|
|
4732
4702
|
{
|
|
4733
4703
|
ref: viewportRef,
|
|
4704
|
+
"aria-busy": busy,
|
|
4734
4705
|
className: [
|
|
4735
4706
|
"gtv-wheel-container",
|
|
4736
4707
|
"gtv-wheel-container--radial",
|
|
@@ -4745,7 +4716,7 @@ function WheelRadialPopCoreCore({
|
|
|
4745
4716
|
},
|
|
4746
4717
|
onPointerDown: panZoom.handlePointerDown,
|
|
4747
4718
|
children: [
|
|
4748
|
-
/* @__PURE__ */
|
|
4719
|
+
/* @__PURE__ */ jsxs12(
|
|
4749
4720
|
"div",
|
|
4750
4721
|
{
|
|
4751
4722
|
ref: stageRef,
|
|
@@ -4759,9 +4730,9 @@ function WheelRadialPopCoreCore({
|
|
|
4759
4730
|
transformOrigin: "0 0"
|
|
4760
4731
|
},
|
|
4761
4732
|
children: [
|
|
4762
|
-
/* @__PURE__ */
|
|
4763
|
-
/* @__PURE__ */
|
|
4764
|
-
isPopExpanded && /* @__PURE__ */
|
|
4733
|
+
/* @__PURE__ */ jsxs12("div", { className: "gtv-wheel-stage", children: [
|
|
4734
|
+
/* @__PURE__ */ jsx16("div", { className: "gtv-wheel-circle", ref: wheelCircleRef }),
|
|
4735
|
+
isPopExpanded && /* @__PURE__ */ jsx16(
|
|
4765
4736
|
"div",
|
|
4766
4737
|
{
|
|
4767
4738
|
className: "gtv-wheel-middle-circle",
|
|
@@ -4770,8 +4741,8 @@ function WheelRadialPopCoreCore({
|
|
|
4770
4741
|
}
|
|
4771
4742
|
}
|
|
4772
4743
|
),
|
|
4773
|
-
/* @__PURE__ */
|
|
4774
|
-
sectorFills.map((sector) => /* @__PURE__ */
|
|
4744
|
+
/* @__PURE__ */ jsxs12("div", { className: "gtv-wheel", children: [
|
|
4745
|
+
sectorFills.map((sector) => /* @__PURE__ */ jsx16(
|
|
4775
4746
|
"div",
|
|
4776
4747
|
{
|
|
4777
4748
|
className: "gtv-wheel-sector",
|
|
@@ -4783,8 +4754,8 @@ function WheelRadialPopCoreCore({
|
|
|
4783
4754
|
},
|
|
4784
4755
|
`sector-${sector.rootId}`
|
|
4785
4756
|
)),
|
|
4786
|
-
/* @__PURE__ */
|
|
4787
|
-
isPopExpanded && /* @__PURE__ */
|
|
4757
|
+
/* @__PURE__ */ jsx16("div", { className: "gtv-wheel-inner-tint" }),
|
|
4758
|
+
isPopExpanded && /* @__PURE__ */ jsx16(
|
|
4788
4759
|
"div",
|
|
4789
4760
|
{
|
|
4790
4761
|
className: "gtv-wheel-middle-tint",
|
|
@@ -4794,7 +4765,7 @@ function WheelRadialPopCoreCore({
|
|
|
4794
4765
|
}
|
|
4795
4766
|
)
|
|
4796
4767
|
] }),
|
|
4797
|
-
/* @__PURE__ */
|
|
4768
|
+
/* @__PURE__ */ jsx16(
|
|
4798
4769
|
"svg",
|
|
4799
4770
|
{
|
|
4800
4771
|
ref: popSvgRef,
|
|
@@ -4803,7 +4774,7 @@ function WheelRadialPopCoreCore({
|
|
|
4803
4774
|
height: svgCanvasRadius * 2
|
|
4804
4775
|
}
|
|
4805
4776
|
),
|
|
4806
|
-
/* @__PURE__ */
|
|
4777
|
+
/* @__PURE__ */ jsx16("div", { className: "gtv-wheel-center-node", children: /* @__PURE__ */ jsx16("div", { className: "gtv-wheel-chip-anchor", children: /* @__PURE__ */ jsx16(
|
|
4807
4778
|
"button",
|
|
4808
4779
|
{
|
|
4809
4780
|
ref: centerChipRef,
|
|
@@ -4841,8 +4812,8 @@ function WheelRadialPopCoreCore({
|
|
|
4841
4812
|
"aria-label": centerNode.name
|
|
4842
4813
|
}
|
|
4843
4814
|
) }) }),
|
|
4844
|
-
/* @__PURE__ */
|
|
4845
|
-
dividerAngles.map((angle, index2) => /* @__PURE__ */
|
|
4815
|
+
/* @__PURE__ */ jsxs12("div", { className: "gtv-wheel", children: [
|
|
4816
|
+
dividerAngles.map((angle, index2) => /* @__PURE__ */ jsx16(
|
|
4846
4817
|
"div",
|
|
4847
4818
|
{
|
|
4848
4819
|
className: "gtv-wheel-divider",
|
|
@@ -4861,12 +4832,12 @@ function WheelRadialPopCoreCore({
|
|
|
4861
4832
|
group.root.id
|
|
4862
4833
|
);
|
|
4863
4834
|
const diameter = 2 * calculateNodeDotRadius(rootItemCount, wheelItemCountRange);
|
|
4864
|
-
return /* @__PURE__ */
|
|
4835
|
+
return /* @__PURE__ */ jsx16(
|
|
4865
4836
|
"div",
|
|
4866
4837
|
{
|
|
4867
4838
|
className: "gtv-wheel-slot",
|
|
4868
4839
|
style: { "--gtv-chip-angle": `${angle}deg` },
|
|
4869
|
-
children: /* @__PURE__ */
|
|
4840
|
+
children: /* @__PURE__ */ jsx16("div", { className: "gtv-wheel-chip-anchor", children: /* @__PURE__ */ jsx16(
|
|
4870
4841
|
"button",
|
|
4871
4842
|
{
|
|
4872
4843
|
type: "button",
|
|
@@ -4908,7 +4879,7 @@ function WheelRadialPopCoreCore({
|
|
|
4908
4879
|
})
|
|
4909
4880
|
] })
|
|
4910
4881
|
] }),
|
|
4911
|
-
regionLabel && index.byId.has(regionLabel.rootId) && /* @__PURE__ */
|
|
4882
|
+
regionLabel && index.byId.has(regionLabel.rootId) && /* @__PURE__ */ jsx16(
|
|
4912
4883
|
"div",
|
|
4913
4884
|
{
|
|
4914
4885
|
ref: regionLabelRef,
|
|
@@ -4926,7 +4897,7 @@ function WheelRadialPopCoreCore({
|
|
|
4926
4897
|
]
|
|
4927
4898
|
}
|
|
4928
4899
|
),
|
|
4929
|
-
panel && /* @__PURE__ */
|
|
4900
|
+
panel && /* @__PURE__ */ jsx16(
|
|
4930
4901
|
InfoPanel,
|
|
4931
4902
|
{
|
|
4932
4903
|
node: panel.node,
|
|
@@ -4953,10 +4924,6 @@ function WheelRadialPopCoreCore({
|
|
|
4953
4924
|
hideTitle: hideInfoPanelTitle,
|
|
4954
4925
|
itemCountLabel,
|
|
4955
4926
|
readOnly,
|
|
4956
|
-
editMode,
|
|
4957
|
-
onEditModeChange,
|
|
4958
|
-
renderTitleEditor,
|
|
4959
|
-
renderParentsEditor,
|
|
4960
4927
|
renderDangerZone,
|
|
4961
4928
|
expanded,
|
|
4962
4929
|
onExpandedChange,
|
|
@@ -4976,8 +4943,8 @@ function WheelRadialPopCoreCore({
|
|
|
4976
4943
|
onZoomIn: onFocusChange && panel.node.id !== focusNodeId && isZoomableNode(nodes, panel.node.id) ? () => onFocusChange(panel.node.id, "zoom-in") : void 0
|
|
4977
4944
|
}
|
|
4978
4945
|
),
|
|
4979
|
-
overlayPanel && /* @__PURE__ */
|
|
4980
|
-
onFocusChange && focusNodeId !== null && /* @__PURE__ */
|
|
4946
|
+
overlayPanel && /* @__PURE__ */ jsx16(OverlayPanel, { ...overlayPanel }),
|
|
4947
|
+
onFocusChange && focusNodeId !== null && /* @__PURE__ */ jsx16(
|
|
4981
4948
|
WheelBreadcrumb,
|
|
4982
4949
|
{
|
|
4983
4950
|
ancestors: index.ancestorsOf(focusNodeId).filter((ancestor) => isZoomableNode(nodes, ancestor.id)),
|
|
@@ -4993,56 +4960,17 @@ function WheelRadialPopCoreCore({
|
|
|
4993
4960
|
},
|
|
4994
4961
|
focusNodeId
|
|
4995
4962
|
),
|
|
4996
|
-
/* @__PURE__ */
|
|
4997
|
-
|
|
4963
|
+
/* @__PURE__ */ jsx16(
|
|
4964
|
+
FloatingControls,
|
|
4998
4965
|
{
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
type: "button",
|
|
5008
|
-
className: [
|
|
5009
|
-
"gtv-zoom-btn",
|
|
5010
|
-
!panZoom.canZoomIn && "gtv-zoom-btn--disabled"
|
|
5011
|
-
].filter(Boolean).join(" "),
|
|
5012
|
-
disabled: !panZoom.canZoomIn,
|
|
5013
|
-
onClick: panZoom.zoomIn,
|
|
5014
|
-
"aria-label": "Zoom in",
|
|
5015
|
-
children: /* @__PURE__ */ jsx14(MdZoomIn5, { className: "gtv-icon", size: 18 })
|
|
5016
|
-
}
|
|
5017
|
-
),
|
|
5018
|
-
/* @__PURE__ */ jsx14(
|
|
5019
|
-
"button",
|
|
5020
|
-
{
|
|
5021
|
-
type: "button",
|
|
5022
|
-
className: [
|
|
5023
|
-
"gtv-zoom-btn",
|
|
5024
|
-
!panZoom.canZoomOut && "gtv-zoom-btn--disabled"
|
|
5025
|
-
].filter(Boolean).join(" "),
|
|
5026
|
-
disabled: !panZoom.canZoomOut,
|
|
5027
|
-
onClick: panZoom.zoomOut,
|
|
5028
|
-
"aria-label": "Zoom out",
|
|
5029
|
-
children: /* @__PURE__ */ jsx14(MdZoomOut4, { className: "gtv-icon", size: 18 })
|
|
5030
|
-
}
|
|
5031
|
-
),
|
|
5032
|
-
/* @__PURE__ */ jsx14(
|
|
5033
|
-
"button",
|
|
5034
|
-
{
|
|
5035
|
-
type: "button",
|
|
5036
|
-
className: "gtv-zoom-btn",
|
|
5037
|
-
onClick: () => panZoom.fitToFrame([
|
|
5038
|
-
wheelCircleRef.current,
|
|
5039
|
-
...queryTreeContentElements(popSvgRef.current)
|
|
5040
|
-
]),
|
|
5041
|
-
"aria-label": "Fit to frame",
|
|
5042
|
-
children: /* @__PURE__ */ jsx14(MdFitScreen4, { className: "gtv-icon", size: 18 })
|
|
5043
|
-
}
|
|
5044
|
-
)
|
|
5045
|
-
] })
|
|
4966
|
+
panZoom,
|
|
4967
|
+
orientation: controlsOrientation,
|
|
4968
|
+
leading: floatingControlsLeading,
|
|
4969
|
+
busy,
|
|
4970
|
+
onFit: () => panZoom.fitToFrame([
|
|
4971
|
+
wheelCircleRef.current,
|
|
4972
|
+
...queryTreeContentElements(popSvgRef.current)
|
|
4973
|
+
])
|
|
5046
4974
|
}
|
|
5047
4975
|
)
|
|
5048
4976
|
]
|
|
@@ -5051,9 +4979,9 @@ function WheelRadialPopCoreCore({
|
|
|
5051
4979
|
}
|
|
5052
4980
|
|
|
5053
4981
|
// src/GenreTreeWheelRadialPopCore.tsx
|
|
5054
|
-
import { jsx as
|
|
4982
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
5055
4983
|
function GenreTreeWheelRadialPopCore(props) {
|
|
5056
|
-
return /* @__PURE__ */
|
|
4984
|
+
return /* @__PURE__ */ jsx17(WheelRadialPopCoreCore, { ...props });
|
|
5057
4985
|
}
|
|
5058
4986
|
|
|
5059
4987
|
// src/GenreTreeOutline.tsx
|
|
@@ -5066,7 +4994,7 @@ import {
|
|
|
5066
4994
|
useState as useState10,
|
|
5067
4995
|
useSyncExternalStore
|
|
5068
4996
|
} from "react";
|
|
5069
|
-
import { Fragment as Fragment5, jsx as
|
|
4997
|
+
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5070
4998
|
function createOutlineStore(initial) {
|
|
5071
4999
|
let state = initial;
|
|
5072
5000
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -5140,9 +5068,9 @@ function OutlineNodeView({
|
|
|
5140
5068
|
const { itemCount } = node;
|
|
5141
5069
|
const children = model.index.childrenByParentId.get(nodeId) ?? [];
|
|
5142
5070
|
const split = isRoot ? model.ringSplitById.get(nodeId) : void 0;
|
|
5143
|
-
const row = /* @__PURE__ */
|
|
5144
|
-
/* @__PURE__ */
|
|
5145
|
-
/* @__PURE__ */
|
|
5071
|
+
const row = /* @__PURE__ */ jsxs13("span", { className: ["gtv-outline-row", isSelected && "gtv-outline-row--selected"].filter(Boolean).join(" "), children: [
|
|
5072
|
+
/* @__PURE__ */ jsx18("span", { className: "gtv-outline-dot", style: { background: model.styleOf(node).fill } }),
|
|
5073
|
+
/* @__PURE__ */ jsx18(
|
|
5146
5074
|
"button",
|
|
5147
5075
|
{
|
|
5148
5076
|
type: "button",
|
|
@@ -5159,16 +5087,16 @@ function OutlineNodeView({
|
|
|
5159
5087
|
children: node.name
|
|
5160
5088
|
}
|
|
5161
5089
|
),
|
|
5162
|
-
/* @__PURE__ */
|
|
5090
|
+
/* @__PURE__ */ jsx18("span", { className: "gtv-outline-count", children: itemCount })
|
|
5163
5091
|
] });
|
|
5164
5092
|
const itemProps = { model, store, callbacks };
|
|
5165
|
-
return /* @__PURE__ */
|
|
5166
|
-
/* @__PURE__ */
|
|
5167
|
-
isOpen && /* @__PURE__ */
|
|
5168
|
-
/* @__PURE__ */
|
|
5169
|
-
/* @__PURE__ */
|
|
5170
|
-
] }) : children.map((child) => /* @__PURE__ */
|
|
5171
|
-
] }) : /* @__PURE__ */
|
|
5093
|
+
return /* @__PURE__ */ jsx18("li", { className: "gtv-outline-item", "data-gtv-node-id": nodeId, children: children.length > 0 ? /* @__PURE__ */ jsxs13("details", { open: isOpen, children: [
|
|
5094
|
+
/* @__PURE__ */ jsx18("summary", { onClick: (event) => handleSummaryClick(event, () => callbacks.toggleOpen(nodeId)), children: row }),
|
|
5095
|
+
isOpen && /* @__PURE__ */ jsx18("ul", { className: "gtv-outline-list", children: split ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
5096
|
+
/* @__PURE__ */ jsx18(OutlineSection, { rootId: nodeId, kind: "core", branches: split.coreBranches, ...itemProps }),
|
|
5097
|
+
/* @__PURE__ */ jsx18(OutlineSection, { rootId: nodeId, kind: "pop", branches: split.popBranches, ...itemProps })
|
|
5098
|
+
] }) : children.map((child) => /* @__PURE__ */ jsx18(OutlineNode, { nodeId: child.id, isRoot: false, ...itemProps }, child.id)) })
|
|
5099
|
+
] }) : /* @__PURE__ */ jsx18("div", { className: "gtv-outline-leaf", children: row }) });
|
|
5172
5100
|
}
|
|
5173
5101
|
var OutlineNode = memo(OutlineNodeView);
|
|
5174
5102
|
var OutlineSection = memo(function OutlineSection2({
|
|
@@ -5182,9 +5110,9 @@ var OutlineSection = memo(function OutlineSection2({
|
|
|
5182
5110
|
const key = sectionKey(kind, rootId);
|
|
5183
5111
|
const isOpen = useOutlineState(store, (s) => s.openIds.has(key));
|
|
5184
5112
|
if (branches.length === 0) return null;
|
|
5185
|
-
return /* @__PURE__ */
|
|
5186
|
-
/* @__PURE__ */
|
|
5187
|
-
isOpen && /* @__PURE__ */
|
|
5113
|
+
return /* @__PURE__ */ jsx18("li", { className: "gtv-outline-item", children: /* @__PURE__ */ jsxs13("details", { open: isOpen, children: [
|
|
5114
|
+
/* @__PURE__ */ jsx18("summary", { onClick: (event) => handleSummaryClick(event, () => callbacks.toggleOpen(key)), children: /* @__PURE__ */ jsx18("span", { className: "gtv-outline-section-label", children: kind === "core" ? "Core" : "Pop" }) }),
|
|
5115
|
+
isOpen && /* @__PURE__ */ jsx18("ul", { className: "gtv-outline-list", children: branches.map(({ child }) => /* @__PURE__ */ jsx18(OutlineNode, { nodeId: child.id, isRoot: false, model, store, callbacks }, child.id)) })
|
|
5188
5116
|
] }) });
|
|
5189
5117
|
});
|
|
5190
5118
|
function GenreTreeOutline(props) {
|
|
@@ -5201,10 +5129,6 @@ function GenreTreeOutline(props) {
|
|
|
5201
5129
|
hideInfoPanelTitle = false,
|
|
5202
5130
|
itemCountLabel,
|
|
5203
5131
|
readOnly,
|
|
5204
|
-
editMode,
|
|
5205
|
-
onEditModeChange,
|
|
5206
|
-
renderTitleEditor,
|
|
5207
|
-
renderParentsEditor,
|
|
5208
5132
|
renderDangerZone,
|
|
5209
5133
|
expanded,
|
|
5210
5134
|
onExpandedChange,
|
|
@@ -5305,12 +5229,12 @@ function GenreTreeOutline(props) {
|
|
|
5305
5229
|
}, [selectedNodeId, store]);
|
|
5306
5230
|
const selectedNode = selectedId === null ? void 0 : index.byId.get(selectedId);
|
|
5307
5231
|
const itemProps = { model, store, callbacks };
|
|
5308
|
-
return /* @__PURE__ */
|
|
5309
|
-
/* @__PURE__ */
|
|
5310
|
-
/* @__PURE__ */
|
|
5311
|
-
model.detachedRoots.length > 0 && /* @__PURE__ */
|
|
5232
|
+
return /* @__PURE__ */ jsxs13("div", { className: ["gtv-outline", selectedNode && "gtv-outline--panel-open", className].filter(Boolean).join(" "), children: [
|
|
5233
|
+
/* @__PURE__ */ jsxs13("div", { className: "gtv-outline-scroll", ref: scrollRef, children: [
|
|
5234
|
+
/* @__PURE__ */ jsx18("ul", { className: "gtv-outline-list gtv-outline-list--roots", children: [model.centerRoot, ...model.ringRoots].map((root) => /* @__PURE__ */ jsx18(OutlineNode, { nodeId: root.id, isRoot: true, ...itemProps }, root.id)) }),
|
|
5235
|
+
model.detachedRoots.length > 0 && /* @__PURE__ */ jsx18("ul", { className: "gtv-outline-list gtv-outline-list--roots gtv-outline-list--detached", children: model.detachedRoots.map((root) => /* @__PURE__ */ jsx18(OutlineNode, { nodeId: root.id, isRoot: true, ...itemProps }, root.id)) })
|
|
5312
5236
|
] }),
|
|
5313
|
-
selectedNode && /* @__PURE__ */
|
|
5237
|
+
selectedNode && /* @__PURE__ */ jsx18(
|
|
5314
5238
|
InfoPanel,
|
|
5315
5239
|
{
|
|
5316
5240
|
node: selectedNode,
|
|
@@ -5331,10 +5255,6 @@ function GenreTreeOutline(props) {
|
|
|
5331
5255
|
hideTitle: hideInfoPanelTitle,
|
|
5332
5256
|
itemCountLabel,
|
|
5333
5257
|
readOnly,
|
|
5334
|
-
editMode,
|
|
5335
|
-
onEditModeChange,
|
|
5336
|
-
renderTitleEditor,
|
|
5337
|
-
renderParentsEditor,
|
|
5338
5258
|
renderDangerZone,
|
|
5339
5259
|
expanded,
|
|
5340
5260
|
onExpandedChange,
|
|
@@ -5353,13 +5273,13 @@ function GenreTreeOutline(props) {
|
|
|
5353
5273
|
} : void 0
|
|
5354
5274
|
}
|
|
5355
5275
|
),
|
|
5356
|
-
overlayPanel && /* @__PURE__ */
|
|
5276
|
+
overlayPanel && /* @__PURE__ */ jsx18(OverlayPanel, { ...overlayPanel })
|
|
5357
5277
|
] });
|
|
5358
5278
|
}
|
|
5359
5279
|
|
|
5360
5280
|
// src/GenreTreeSkeleton.tsx
|
|
5361
5281
|
import { useId } from "react";
|
|
5362
|
-
import { Fragment as Fragment6, jsx as
|
|
5282
|
+
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5363
5283
|
var CARD_FILL = "#F4F4F5";
|
|
5364
5284
|
var CARD_BORDER_COLOR = "#E4E4E7";
|
|
5365
5285
|
var CONNECTOR_COLOR2 = "#D4D4D8";
|
|
@@ -5464,8 +5384,8 @@ function SkeletonCard({
|
|
|
5464
5384
|
card,
|
|
5465
5385
|
rootAccent
|
|
5466
5386
|
}) {
|
|
5467
|
-
return /* @__PURE__ */
|
|
5468
|
-
/* @__PURE__ */
|
|
5387
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
5388
|
+
/* @__PURE__ */ jsx19(
|
|
5469
5389
|
"rect",
|
|
5470
5390
|
{
|
|
5471
5391
|
x: card.x,
|
|
@@ -5479,7 +5399,7 @@ function SkeletonCard({
|
|
|
5479
5399
|
strokeWidth: rootAccent ? 1.5 : 1
|
|
5480
5400
|
}
|
|
5481
5401
|
),
|
|
5482
|
-
rootAccent && /* @__PURE__ */
|
|
5402
|
+
rootAccent && /* @__PURE__ */ jsx19(
|
|
5483
5403
|
"circle",
|
|
5484
5404
|
{
|
|
5485
5405
|
cx: card.x + 18,
|
|
@@ -5497,9 +5417,9 @@ function GenreTreeSkeleton() {
|
|
|
5497
5417
|
const animationName = `genre-tree-skeleton-sweep-${uid}`;
|
|
5498
5418
|
const shimmerBandClass = `genre-tree-skeleton-shimmer-band-${uid}`;
|
|
5499
5419
|
const sweepDistance = VIEWBOX_WIDTH + SHIMMER_BAND_WIDTH;
|
|
5500
|
-
return /* @__PURE__ */
|
|
5501
|
-
/* @__PURE__ */
|
|
5502
|
-
/* @__PURE__ */
|
|
5420
|
+
return /* @__PURE__ */ jsxs14("div", { className: "gtv-skeleton", children: [
|
|
5421
|
+
/* @__PURE__ */ jsx19("span", { className: "gtv-skeleton-sr-only", children: "Loading genre tree\u2026" }),
|
|
5422
|
+
/* @__PURE__ */ jsxs14(
|
|
5503
5423
|
"svg",
|
|
5504
5424
|
{
|
|
5505
5425
|
viewBox: `0 0 ${VIEWBOX_WIDTH} ${VIEWBOX_HEIGHT}`,
|
|
@@ -5508,7 +5428,7 @@ function GenreTreeSkeleton() {
|
|
|
5508
5428
|
className: "gtv-skeleton-svg",
|
|
5509
5429
|
"aria-hidden": "true",
|
|
5510
5430
|
children: [
|
|
5511
|
-
/* @__PURE__ */
|
|
5431
|
+
/* @__PURE__ */ jsx19("style", { children: `
|
|
5512
5432
|
@keyframes ${animationName} {
|
|
5513
5433
|
from { transform: translateX(0); }
|
|
5514
5434
|
to { transform: translateX(${sweepDistance}px); }
|
|
@@ -5522,9 +5442,9 @@ function GenreTreeSkeleton() {
|
|
|
5522
5442
|
}
|
|
5523
5443
|
}
|
|
5524
5444
|
` }),
|
|
5525
|
-
/* @__PURE__ */
|
|
5526
|
-
/* @__PURE__ */
|
|
5527
|
-
/* @__PURE__ */
|
|
5445
|
+
/* @__PURE__ */ jsxs14("defs", { children: [
|
|
5446
|
+
/* @__PURE__ */ jsxs14("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "1", y2: "0", children: [
|
|
5447
|
+
/* @__PURE__ */ jsx19(
|
|
5528
5448
|
"stop",
|
|
5529
5449
|
{
|
|
5530
5450
|
offset: "0%",
|
|
@@ -5532,7 +5452,7 @@ function GenreTreeSkeleton() {
|
|
|
5532
5452
|
stopOpacity: 0
|
|
5533
5453
|
}
|
|
5534
5454
|
),
|
|
5535
|
-
/* @__PURE__ */
|
|
5455
|
+
/* @__PURE__ */ jsx19(
|
|
5536
5456
|
"stop",
|
|
5537
5457
|
{
|
|
5538
5458
|
offset: "50%",
|
|
@@ -5540,7 +5460,7 @@ function GenreTreeSkeleton() {
|
|
|
5540
5460
|
stopOpacity: 0.9
|
|
5541
5461
|
}
|
|
5542
5462
|
),
|
|
5543
|
-
/* @__PURE__ */
|
|
5463
|
+
/* @__PURE__ */ jsx19(
|
|
5544
5464
|
"stop",
|
|
5545
5465
|
{
|
|
5546
5466
|
offset: "100%",
|
|
@@ -5549,8 +5469,8 @@ function GenreTreeSkeleton() {
|
|
|
5549
5469
|
}
|
|
5550
5470
|
)
|
|
5551
5471
|
] }),
|
|
5552
|
-
/* @__PURE__ */
|
|
5553
|
-
ALL_LINKS.map((link, i) => /* @__PURE__ */
|
|
5472
|
+
/* @__PURE__ */ jsxs14("mask", { id: maskId, children: [
|
|
5473
|
+
ALL_LINKS.map((link, i) => /* @__PURE__ */ jsx19(
|
|
5554
5474
|
"path",
|
|
5555
5475
|
{
|
|
5556
5476
|
d: connectorPath(link.from, link.to),
|
|
@@ -5560,7 +5480,7 @@ function GenreTreeSkeleton() {
|
|
|
5560
5480
|
},
|
|
5561
5481
|
`link-mask-${i}`
|
|
5562
5482
|
)),
|
|
5563
|
-
ALL_CARDS.map(({ card }, i) => /* @__PURE__ */
|
|
5483
|
+
ALL_CARDS.map(({ card }, i) => /* @__PURE__ */ jsx19(
|
|
5564
5484
|
"rect",
|
|
5565
5485
|
{
|
|
5566
5486
|
x: card.x,
|
|
@@ -5575,7 +5495,7 @@ function GenreTreeSkeleton() {
|
|
|
5575
5495
|
))
|
|
5576
5496
|
] })
|
|
5577
5497
|
] }),
|
|
5578
|
-
ALL_LINKS.map((link, i) => /* @__PURE__ */
|
|
5498
|
+
ALL_LINKS.map((link, i) => /* @__PURE__ */ jsx19(
|
|
5579
5499
|
"path",
|
|
5580
5500
|
{
|
|
5581
5501
|
d: connectorPath(link.from, link.to),
|
|
@@ -5585,8 +5505,8 @@ function GenreTreeSkeleton() {
|
|
|
5585
5505
|
},
|
|
5586
5506
|
`link-${i}`
|
|
5587
5507
|
)),
|
|
5588
|
-
ALL_CARDS.map(({ card, rootAccent }, i) => /* @__PURE__ */
|
|
5589
|
-
/* @__PURE__ */
|
|
5508
|
+
ALL_CARDS.map(({ card, rootAccent }, i) => /* @__PURE__ */ jsx19(SkeletonCard, { card, rootAccent }, `card-${i}`)),
|
|
5509
|
+
/* @__PURE__ */ jsx19("g", { mask: `url(#${maskId})`, children: /* @__PURE__ */ jsx19(
|
|
5590
5510
|
"rect",
|
|
5591
5511
|
{
|
|
5592
5512
|
className: shimmerBandClass,
|
|
@@ -5605,7 +5525,7 @@ function GenreTreeSkeleton() {
|
|
|
5605
5525
|
|
|
5606
5526
|
// src/GenreTreeWheelSkeleton.tsx
|
|
5607
5527
|
import { useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef10 } from "react";
|
|
5608
|
-
import { jsx as
|
|
5528
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5609
5529
|
var SHAPE_COLOR = "#D4D4D8";
|
|
5610
5530
|
var SECTOR_FILL_OPACITY = 0.22;
|
|
5611
5531
|
var INNER_TINT_OPACITY = 0.55;
|
|
@@ -5750,8 +5670,8 @@ function GenreTreeWheelSkeleton() {
|
|
|
5750
5670
|
sharedStartTime ??= animation.startTime ?? document.timeline.currentTime;
|
|
5751
5671
|
animation.startTime = sharedStartTime;
|
|
5752
5672
|
}, []);
|
|
5753
|
-
return /* @__PURE__ */
|
|
5754
|
-
/* @__PURE__ */
|
|
5673
|
+
return /* @__PURE__ */ jsxs15("div", { className: "gtv-wheel-skeleton", children: [
|
|
5674
|
+
/* @__PURE__ */ jsx20(
|
|
5755
5675
|
"div",
|
|
5756
5676
|
{
|
|
5757
5677
|
className: "gtv-wheel-skeleton-sector-layer",
|
|
@@ -5759,8 +5679,8 @@ function GenreTreeWheelSkeleton() {
|
|
|
5759
5679
|
"aria-hidden": "true"
|
|
5760
5680
|
}
|
|
5761
5681
|
),
|
|
5762
|
-
/* @__PURE__ */
|
|
5763
|
-
/* @__PURE__ */
|
|
5682
|
+
/* @__PURE__ */ jsx20("span", { className: "gtv-skeleton-sr-only", children: "Loading genre tree\u2026" }),
|
|
5683
|
+
/* @__PURE__ */ jsxs15(
|
|
5764
5684
|
"svg",
|
|
5765
5685
|
{
|
|
5766
5686
|
viewBox: `${CANVAS_ORIGIN} ${CANVAS_ORIGIN} ${CANVAS_SIZE} ${CANVAS_SIZE}`,
|
|
@@ -5768,14 +5688,14 @@ function GenreTreeWheelSkeleton() {
|
|
|
5768
5688
|
className: "gtv-wheel-skeleton-svg",
|
|
5769
5689
|
"aria-hidden": "true",
|
|
5770
5690
|
children: [
|
|
5771
|
-
/* @__PURE__ */
|
|
5772
|
-
/* @__PURE__ */
|
|
5773
|
-
/* @__PURE__ */
|
|
5774
|
-
/* @__PURE__ */
|
|
5775
|
-
/* @__PURE__ */
|
|
5691
|
+
/* @__PURE__ */ jsxs15("defs", { children: [
|
|
5692
|
+
/* @__PURE__ */ jsxs15("radialGradient", { id: mainstreamId, children: [
|
|
5693
|
+
/* @__PURE__ */ jsx20("stop", { offset: "0%", stopColor: "#FFFFFF", stopOpacity: 0.45 }),
|
|
5694
|
+
/* @__PURE__ */ jsx20("stop", { offset: "65%", stopColor: "#FFFFFF", stopOpacity: 0.15 }),
|
|
5695
|
+
/* @__PURE__ */ jsx20("stop", { offset: "100%", stopColor: "#FFFFFF", stopOpacity: 0 })
|
|
5776
5696
|
] }),
|
|
5777
|
-
/* @__PURE__ */
|
|
5778
|
-
LINKS.map((link, i) => /* @__PURE__ */
|
|
5697
|
+
/* @__PURE__ */ jsxs15("g", { id: shapesId, children: [
|
|
5698
|
+
LINKS.map((link, i) => /* @__PURE__ */ jsx20(
|
|
5779
5699
|
"path",
|
|
5780
5700
|
{
|
|
5781
5701
|
d: link.d,
|
|
@@ -5787,21 +5707,21 @@ function GenreTreeWheelSkeleton() {
|
|
|
5787
5707
|
},
|
|
5788
5708
|
`link-${i}`
|
|
5789
5709
|
)),
|
|
5790
|
-
DOTS.map((dot, i) => /* @__PURE__ */
|
|
5710
|
+
DOTS.map((dot, i) => /* @__PURE__ */ jsx20("circle", { cx: dot.point.x, cy: dot.point.y, r: dot.r, fill: "currentColor" }, `dot-${i}`))
|
|
5791
5711
|
] })
|
|
5792
5712
|
] }),
|
|
5793
|
-
/* @__PURE__ */
|
|
5794
|
-
/* @__PURE__ */
|
|
5795
|
-
/* @__PURE__ */
|
|
5713
|
+
/* @__PURE__ */ jsx20("circle", { cx: 0, cy: 0, r: RING_RADIUS, fill: "#FFFFFF", fillOpacity: INNER_TINT_OPACITY }),
|
|
5714
|
+
/* @__PURE__ */ jsx20("circle", { cx: 0, cy: 0, r: MAINSTREAM_RADIUS, fill: `url(#${mainstreamId})` }),
|
|
5715
|
+
/* @__PURE__ */ jsx20("use", { href: `#${shapesId}`, color: SHAPE_COLOR })
|
|
5796
5716
|
]
|
|
5797
5717
|
}
|
|
5798
5718
|
),
|
|
5799
|
-
/* @__PURE__ */
|
|
5719
|
+
/* @__PURE__ */ jsx20("div", { className: "gtv-wheel-skeleton-shimmer", "aria-hidden": "true", children: /* @__PURE__ */ jsx20("div", { ref: wedgeRef, className: "gtv-wheel-skeleton-shimmer-wedge" }) })
|
|
5800
5720
|
] });
|
|
5801
5721
|
}
|
|
5802
5722
|
|
|
5803
5723
|
// src/GenreTreeOutlineSkeleton.tsx
|
|
5804
|
-
import { jsx as
|
|
5724
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5805
5725
|
var ROWS = [
|
|
5806
5726
|
{ depth: 0, width: 38 },
|
|
5807
5727
|
{ depth: 0, width: 26 },
|
|
@@ -5813,9 +5733,9 @@ var ROWS = [
|
|
|
5813
5733
|
{ depth: 0, width: 22 }
|
|
5814
5734
|
];
|
|
5815
5735
|
function GenreTreeOutlineSkeleton() {
|
|
5816
|
-
return /* @__PURE__ */
|
|
5817
|
-
/* @__PURE__ */
|
|
5818
|
-
ROWS.map((row, i) => /* @__PURE__ */
|
|
5736
|
+
return /* @__PURE__ */ jsxs16("div", { className: "gtv-skeleton gtv-outline-skeleton", children: [
|
|
5737
|
+
/* @__PURE__ */ jsx21("span", { className: "gtv-skeleton-sr-only", children: "Loading genre tree\u2026" }),
|
|
5738
|
+
ROWS.map((row, i) => /* @__PURE__ */ jsx21(
|
|
5819
5739
|
"div",
|
|
5820
5740
|
{
|
|
5821
5741
|
className: "gtv-outline-skeleton-row",
|
|
@@ -5828,13 +5748,13 @@ function GenreTreeOutlineSkeleton() {
|
|
|
5828
5748
|
}
|
|
5829
5749
|
|
|
5830
5750
|
// src/GenreTreeViewSkeleton.tsx
|
|
5831
|
-
import { jsx as
|
|
5751
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
5832
5752
|
function GenreTreeViewSkeleton({ viewMode }) {
|
|
5833
5753
|
if (viewMode === "wheel" || viewMode === "pop-core") {
|
|
5834
|
-
return /* @__PURE__ */
|
|
5754
|
+
return /* @__PURE__ */ jsx22("div", { className: "gtv-view-skeleton-wheel-wrapper", children: /* @__PURE__ */ jsx22(GenreTreeWheelSkeleton, {}) });
|
|
5835
5755
|
}
|
|
5836
|
-
if (viewMode === "outline") return /* @__PURE__ */
|
|
5837
|
-
return /* @__PURE__ */
|
|
5756
|
+
if (viewMode === "outline") return /* @__PURE__ */ jsx22(GenreTreeOutlineSkeleton, {});
|
|
5757
|
+
return /* @__PURE__ */ jsx22(GenreTreeSkeleton, {});
|
|
5838
5758
|
}
|
|
5839
5759
|
export {
|
|
5840
5760
|
DEFAULT_FRAME_HEIGHT,
|