@behindthemusictree/app-kit-ui 42.0.2 → 43.0.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.
@@ -1,15 +1,16 @@
1
1
  import {
2
2
  BasePopup_default,
3
3
  InternalErrorPopup,
4
+ PopupButtons,
4
5
  Toast
5
6
  } from "./chunk-2GH7CSCE.js";
6
7
 
7
8
  // src/genre-tree/GenreTreeView.tsx
8
- import { useCallback as useCallback6, useDeferredValue as useDeferredValue2, useEffect as useEffect6, useMemo as useMemo8, useRef as useRef3, useState as useState10 } from "react";
9
+ import { useCallback as useCallback6, useDeferredValue as useDeferredValue2, useEffect as useEffect6, useMemo as useMemo8, useRef as useRef3, useState as useState11 } from "react";
9
10
  import { useIsMutating } from "@tanstack/react-query";
10
11
  import { Plus as Plus2 } from "lucide-react";
11
12
  import { Maximize2 as Maximize22, Minimize2 as Minimize22 } from "lucide-react";
12
- import { IconTextButton, IconButton as IconButton2, Button, SegmentedControl as SegmentedControl2, DetailPanel as DetailPanel2, useObscuredInset } from "@behindthemusictree/ui";
13
+ import { IconTextButton, IconButton as IconButton2, Button as Button2, SegmentedControl as SegmentedControl2, DetailPanel as DetailPanel2, useObscuredInset } from "@behindthemusictree/ui";
13
14
  import {
14
15
  GenreTreeWheelSkeleton,
15
16
  GenreTreeViewSkeleton,
@@ -1608,7 +1609,16 @@ function useGenreDetailContent({
1608
1609
  onSelectNode: selectGenre
1609
1610
  }
1610
1611
  );
1611
- const ancestors = /* @__PURE__ */ jsx25(GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
1612
+ const ancestors = /* @__PURE__ */ jsx25(
1613
+ GenreNodeAncestors,
1614
+ {
1615
+ node: view.node,
1616
+ fill: view.fill,
1617
+ textColor: view.textColor,
1618
+ ancestorNodes: view.ancestorNodes,
1619
+ onSelectNode: selectGenre
1620
+ }
1621
+ );
1612
1622
  return {
1613
1623
  name: detail.name,
1614
1624
  title: detail.name,
@@ -1682,11 +1692,12 @@ function GenreDetailPanel({
1682
1692
  }
1683
1693
 
1684
1694
  // src/genre-tree/ChangeParentPopup.tsx
1685
- import { useEffect as useEffect5, useMemo as useMemo7 } from "react";
1695
+ import { useEffect as useEffect5, useMemo as useMemo7, useState as useState8 } from "react";
1686
1696
  import {
1687
1697
  getReparentCandidates,
1688
1698
  useUpdateGenre
1689
1699
  } from "@behindthemusictree/app-kit/genre-tree";
1700
+ import { Button } from "@behindthemusictree/ui";
1690
1701
  import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1691
1702
  function ChangeParentPopup({
1692
1703
  genrePlaylist,
@@ -1701,20 +1712,22 @@ function ChangeParentPopup({
1701
1712
  () => getReparentCandidates(genrePlaylists, genrePlaylist.uuid),
1702
1713
  [genrePlaylists, genrePlaylist.uuid]
1703
1714
  );
1704
- const handleSelect = (newParent) => {
1715
+ const [confirmingRoot, setConfirmingRoot] = useState8(false);
1716
+ const handleMove = (to) => {
1705
1717
  const genre = genrePlaylist.criteria.uuid;
1706
1718
  const parentPlaylistUuid = genrePlaylist.parent?.uuid;
1707
1719
  const from = parentPlaylistUuid ? genrePlaylists.find(({ uuid }) => uuid === parentPlaylistUuid)?.criteria?.uuid ?? null : null;
1708
1720
  mutate(
1709
- { uuid: genre, data: { parent: newParent.criteria.uuid } },
1721
+ { uuid: genre, data: { parent: to } },
1710
1722
  {
1711
1723
  onSuccess: () => {
1712
1724
  onClose();
1713
- onParentChanged?.({ genre, from, to: newParent.criteria.uuid });
1725
+ onParentChanged?.({ genre, from, to });
1714
1726
  }
1715
1727
  }
1716
1728
  );
1717
1729
  };
1730
+ const handleSelect = (newParent) => handleMove(newParent.criteria.uuid);
1718
1731
  useEffect5(() => {
1719
1732
  const handleKeyDown = (event) => {
1720
1733
  if (event.key === "Escape") onClose();
@@ -1727,6 +1740,18 @@ function ChangeParentPopup({
1727
1740
  "Current parent: ",
1728
1741
  genrePlaylist.parent?.name ?? "none"
1729
1742
  ] }),
1743
+ genrePlaylist.parent && (confirmingRoot ? /* @__PURE__ */ jsxs17("div", { className: "mb-3 text-sm", children: [
1744
+ /* @__PURE__ */ jsxs17("p", { className: "mb-2", children: [
1745
+ genrePlaylist.name,
1746
+ " and its descendants will no longer be under ",
1747
+ genrePlaylist.parent.name,
1748
+ "."
1749
+ ] }),
1750
+ /* @__PURE__ */ jsxs17(PopupButtons, { alignment: "left", children: [
1751
+ /* @__PURE__ */ jsx26(Button, { disabled: isPending, onClick: () => handleMove(null), children: "Confirm" }),
1752
+ /* @__PURE__ */ jsx26(Button, { variant: "secondary", disabled: isPending, onClick: () => setConfirmingRoot(false), children: "Back" })
1753
+ ] })
1754
+ ] }) : /* @__PURE__ */ jsx26("div", { className: "mb-3", children: /* @__PURE__ */ jsx26(Button, { variant: "secondary", onClick: () => setConfirmingRoot(true), children: "Make root" }) })),
1730
1755
  /* @__PURE__ */ jsx26("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx26(
1731
1756
  GenreSearch,
1732
1757
  {
@@ -1965,7 +1990,7 @@ function ArtistDiscography({ albums }) {
1965
1990
  }
1966
1991
 
1967
1992
  // src/genre-tree/artist/ArtistSongs.tsx
1968
- import { useState as useState8 } from "react";
1993
+ import { useState as useState9 } from "react";
1969
1994
  import { keepPreviousData } from "@tanstack/react-query";
1970
1995
  import { Pagination, PanelSection as PanelSection5, Skeleton as Skeleton4 } from "@behindthemusictree/ui";
1971
1996
  import { usePlayer as usePlayer9 } from "@behindthemusictree/app-kit/player";
@@ -2109,8 +2134,8 @@ var SORTS = [
2109
2134
  { ordering: "-albumYear", label: "Year" }
2110
2135
  ];
2111
2136
  function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
2112
- const [page, setPage] = useState8(1);
2113
- const [ordering, setOrdering] = useState8("title");
2137
+ const [page, setPage] = useState9(1);
2138
+ const [ordering, setOrdering] = useState9("title");
2114
2139
  const { playNewTrackListFromArtist } = useTrackList5();
2115
2140
  const { playerTrackObject } = usePlayer9();
2116
2141
  const { data, isPending, isError } = usePlaybackQuery({
@@ -2249,7 +2274,7 @@ import {
2249
2274
  } from "@behindthemusictree/app-kit/genre-tree";
2250
2275
 
2251
2276
  // src/genre-tree/song/SongPanelContent.tsx
2252
- import { useState as useState9 } from "react";
2277
+ import { useState as useState10 } from "react";
2253
2278
  import { Pause as Pause3, Play as Play3 } from "lucide-react";
2254
2279
  import { ActionBand as ActionBand3, ActionButton as ActionButton5, FieldList as FieldList2, PANEL_LABEL_CLASS, PanelBleed as PanelBleed3, PanelSection as PanelSection6, Skeleton as Skeleton6 } from "@behindthemusictree/ui";
2255
2280
  import { PlayStates as PlayStates3, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
@@ -2265,7 +2290,7 @@ var numberFormat = new Intl.NumberFormat("en");
2265
2290
  var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
2266
2291
  var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
2267
2292
  function SongHistory({ uuid, getBackendBaseUrl }) {
2268
- const [open, setOpen] = useState9(false);
2293
+ const [open, setOpen] = useState10(false);
2269
2294
  const history = useSongHistory(uuid, getBackendBaseUrl, open);
2270
2295
  let body = null;
2271
2296
  if (history.status === "loading") body = /* @__PURE__ */ jsx37(Skeleton6, { className: "h-10", "aria-busy": "true" });
@@ -2553,17 +2578,17 @@ function GenreTreeView({
2553
2578
  }) {
2554
2579
  const getShareUrlRef = useRef3(getShareUrl);
2555
2580
  getShareUrlRef.current = getShareUrl;
2556
- const [internalArtistUuid, setInternalArtistUuid] = useState10(null);
2581
+ const [internalArtistUuid, setInternalArtistUuid] = useState11(null);
2557
2582
  const isArtistControlled = controlledArtistUuid !== void 0;
2558
2583
  const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
2559
- const [internalSongUuid, setInternalSongUuid] = useState10(null);
2584
+ const [internalSongUuid, setInternalSongUuid] = useState11(null);
2560
2585
  const isSongControlled = controlledSongUuid !== void 0;
2561
2586
  const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
2562
2587
  const changeSong = (uuid) => {
2563
2588
  if (!isSongControlled) setInternalSongUuid(uuid);
2564
2589
  onSongUuidChange?.(uuid);
2565
2590
  };
2566
- const [internalSizeMetric, setInternalSizeMetric] = useState10("songs");
2591
+ const [internalSizeMetric, setInternalSizeMetric] = useState11("songs");
2567
2592
  const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
2568
2593
  const deferredSizeMetric = useDeferredValue2(sizeMetric);
2569
2594
  const changeSizeMetric = (metric) => {
@@ -2607,7 +2632,7 @@ function GenreTreeView({
2607
2632
  artistUuid
2608
2633
  });
2609
2634
  const restoreRevision = viewportRestore?.revision;
2610
- const [stackedRestoreOwner, setStackedRestoreOwner] = useState10({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2635
+ const [stackedRestoreOwner, setStackedRestoreOwner] = useState11({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2611
2636
  let restoreRootUuid = stackedRestoreOwner.rootUuid;
2612
2637
  if (stackedRestoreOwner.revision !== restoreRevision) {
2613
2638
  restoreRootUuid = selectedGenrePlaylist?.root.uuid;
@@ -2644,8 +2669,8 @@ function GenreTreeView({
2644
2669
  (song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
2645
2670
  [renderSongLink]
2646
2671
  );
2647
- const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
2648
- const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
2672
+ const [expandedSongUuid, setExpandedSongUuid] = useState11(null);
2673
+ const [expandedArtistUuid, setExpandedArtistUuid] = useState11(null);
2649
2674
  const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
2650
2675
  const songBaseUrl = getBackendBaseUrl;
2651
2676
  const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
@@ -2692,8 +2717,8 @@ function GenreTreeView({
2692
2717
  }
2693
2718
  });
2694
2719
  const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
2695
- const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState10(false);
2696
- const [uncontrolledExpanded, setUncontrolledExpanded] = useState10(false);
2720
+ const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState11(false);
2721
+ const [uncontrolledExpanded, setUncontrolledExpanded] = useState11(false);
2697
2722
  const isCollapsed = collapsed ?? uncontrolledCollapsed;
2698
2723
  const isExpanded = expanded ?? uncontrolledExpanded;
2699
2724
  const changeCollapsed = (next) => {
@@ -2707,10 +2732,10 @@ function GenreTreeView({
2707
2732
  useEffect6(() => {
2708
2733
  setUncontrolledCollapsed(false);
2709
2734
  }, [selectedGenreUuid, artistUuid, songUuid]);
2710
- const [isWheelRevealed, setIsWheelRevealed] = useState10(false);
2735
+ const [isWheelRevealed, setIsWheelRevealed] = useState11(false);
2711
2736
  const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
2712
2737
  const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
2713
- const [resolveStyle, setResolveStyle] = useState10(null);
2738
+ const [resolveStyle, setResolveStyle] = useState11(null);
2714
2739
  const handleNodeStyleResolverChange = useCallback6(
2715
2740
  (resolver) => setResolveStyle(() => resolver),
2716
2741
  []
@@ -2727,7 +2752,7 @@ function GenreTreeView({
2727
2752
  );
2728
2753
  const treeStyles = useMemo8(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
2729
2754
  const validSelectedGenreUuid = toGenreUuid(selectedGenreUuid);
2730
- const [selectionHistory, setSelectionHistory] = useState10({ current: validSelectedGenreUuid, previous: null });
2755
+ const [selectionHistory, setSelectionHistory] = useState11({ current: validSelectedGenreUuid, previous: null });
2731
2756
  if (selectionHistory.current !== validSelectedGenreUuid) {
2732
2757
  setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
2733
2758
  }
@@ -2937,7 +2962,7 @@ function GenreTreeView({
2937
2962
  role: "group",
2938
2963
  "aria-label": "Tree display options",
2939
2964
  children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx40(
2940
- Button,
2965
+ Button2,
2941
2966
  {
2942
2967
  variant: allowWheelRotation ? "default" : "outline",
2943
2968
  size: "sm",
@@ -3300,7 +3325,8 @@ function TrackListSidebar({
3300
3325
  }
3301
3326
 
3302
3327
  // src/genre-tree/PlayerPanel.tsx
3303
- import { useEffect as useEffect8, useState as useState11 } from "react";
3328
+ import { useEffect as useEffect8, useState as useState12 } from "react";
3329
+ import { X } from "lucide-react";
3304
3330
  import { twMerge } from "tailwind-merge";
3305
3331
  import {
3306
3332
  usePlayer as usePlayer12,
@@ -3309,7 +3335,7 @@ import {
3309
3335
  import {
3310
3336
  useTrackListSidebarVisibility
3311
3337
  } from "@behindthemusictree/app-kit/genre-tree";
3312
- import { PanelEdgeTab } from "@behindthemusictree/ui";
3338
+ import { IconButton as IconButton3, PanelEdgeTab } from "@behindthemusictree/ui";
3313
3339
 
3314
3340
  // src/genre-tree/PlayerControls.tsx
3315
3341
  import { Pause as Pause4, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
@@ -3434,14 +3460,14 @@ function PlayerPanel({
3434
3460
  renderArtistLink,
3435
3461
  renderSongLink
3436
3462
  }) {
3437
- const { playerTrackObject, retryPlayback } = usePlayer12();
3463
+ const { playerTrackObject, retryPlayback, stop } = usePlayer12();
3438
3464
  const { toggleTrackListSidebar, isTrackListSidebarVisible } = useTrackListSidebarVisibility();
3439
- const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState11("");
3465
+ const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState12("");
3440
3466
  const loadedTrackTitle = playerTrackObject?.track.title;
3441
3467
  useEffect8(() => {
3442
3468
  if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
3443
3469
  }, [loadedTrackTitle]);
3444
- const [uncontrolledExtended, setUncontrolledExtended] = useState11(false);
3470
+ const [uncontrolledExtended, setUncontrolledExtended] = useState12(false);
3445
3471
  const isExtendRequested = expanded ?? uncontrolledExtended;
3446
3472
  const setIsExtendRequested = (next) => {
3447
3473
  setUncontrolledExtended(next);
@@ -3494,7 +3520,10 @@ function PlayerPanel({
3494
3520
  ),
3495
3521
  children: [
3496
3522
  /* @__PURE__ */ jsxs31("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
3497
- /* @__PURE__ */ jsx43("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx43("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
3523
+ /* @__PURE__ */ jsxs31("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: [
3524
+ /* @__PURE__ */ jsx43("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }),
3525
+ playerTrackObject && /* @__PURE__ */ jsx43(IconButton3, { "aria-label": "Close player", onClick: stop, children: /* @__PURE__ */ jsx43(X, { "aria-hidden": "true", className: "h-4 w-4" }) })
3526
+ ] }),
3498
3527
  /* @__PURE__ */ jsxs31("div", { className: "relative w-full shrink-0", children: [
3499
3528
  /* @__PURE__ */ jsx43(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
3500
3529
  playerTrackObject?.loadError && /* @__PURE__ */ jsxs31("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
@@ -3568,7 +3597,7 @@ function Rating({ rating, handleChange }) {
3568
3597
  }
3569
3598
 
3570
3599
  // src/genre-tree/EntityDetailPanel.tsx
3571
- import { useState as useState12 } from "react";
3600
+ import { useState as useState13 } from "react";
3572
3601
  import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
3573
3602
  import { Fragment as Fragment17, jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
3574
3603
  function EntityDetailPanel({
@@ -3587,8 +3616,8 @@ function EntityDetailPanel({
3587
3616
  edgeTab,
3588
3617
  ...navigation
3589
3618
  }) {
3590
- const [expandedSongUuid, setExpandedSongUuid] = useState12(null);
3591
- const [expandedArtistUuid, setExpandedArtistUuid] = useState12(null);
3619
+ const [expandedSongUuid, setExpandedSongUuid] = useState13(null);
3620
+ const [expandedArtistUuid, setExpandedArtistUuid] = useState13(null);
3592
3621
  const panel = useEntityPanel({
3593
3622
  scope,
3594
3623
  getBackendBaseUrl,
@@ -3658,4 +3687,4 @@ export {
3658
3687
  GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
3659
3688
  GenreTreeOutlineSkeleton
3660
3689
  };
3661
- //# sourceMappingURL=chunk-PVYUC2PN.js.map
3690
+ //# sourceMappingURL=chunk-UTUU463Q.js.map