@behindthemusictree/app-kit-ui 37.0.0 → 37.1.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.
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/genre-tree/index.ts
21
21
  var genre_tree_exports = {};
22
22
  __export(genre_tree_exports, {
23
+ EntityDetailPanel: () => EntityDetailPanel,
23
24
  GenreDetailPanel: () => GenreDetailPanel,
24
25
  GenreInfoPanelBody: () => GenreInfoPanelBody,
25
26
  GenreNodeActionBand: () => GenreNodeActionBand,
@@ -39,6 +40,7 @@ __export(genre_tree_exports, {
39
40
  TrackPositionPlayPause: () => TrackPositionPlayPause,
40
41
  searchStatus: () => searchStatus,
41
42
  useArtistSearchGroup: () => useArtistSearchGroup,
43
+ useEntityPanel: () => useEntityPanel,
42
44
  useGenrePlaylistPlayback: () => useGenrePlaylistPlayback,
43
45
  useGenreRemoteSearchGroup: () => useGenreRemoteSearchGroup,
44
46
  useSongSearchGroup: () => useSongSearchGroup
@@ -2410,15 +2412,8 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
2410
2412
  }
2411
2413
  );
2412
2414
  }
2413
- function SongPanelContent({
2414
- song,
2415
- scope,
2416
- getBackendBaseUrl,
2417
- shareUrl,
2418
- renderArtistLink,
2419
- genrePath,
2420
- onSelectGenre
2421
- }) {
2415
+ function SongPanelContent(props) {
2416
+ const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;
2422
2417
  const { playNewTrackListFromTrackUuid } = (0, import_genre_tree26.useTrackList)();
2423
2418
  const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player11.usePlayer)();
2424
2419
  const unplayableReason = (0, import_genre_tree26.songUnplayableReason)(song);
@@ -2428,12 +2423,14 @@ function SongPanelContent({
2428
2423
  const musicBrainzUrl = (0, import_genre_tree26.musicBrainzRecordingUrl)(song);
2429
2424
  const fields = [];
2430
2425
  if (song.genre) {
2431
- const path = genrePath.length > 0 ? genrePath : null;
2426
+ const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;
2427
+ const { onSelectGenre } = props;
2428
+ const genre = song.genre;
2432
2429
  fields.push({
2433
2430
  label: "Genre",
2434
- value: path ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
2431
+ value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
2435
2432
  index > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
2436
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
2433
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
2437
2434
  ] }, genrePlaylist.uuid)) }) : song.genre.name
2438
2435
  });
2439
2436
  } else {
@@ -2499,11 +2496,10 @@ function useSongPanel({
2499
2496
  getBackendBaseUrl,
2500
2497
  getShareUrl,
2501
2498
  renderArtistLink,
2502
- getGenrePath,
2503
- onSelectGenre,
2504
2499
  expanded,
2505
2500
  onExpandedChange,
2506
- onClose
2501
+ onClose,
2502
+ ...navigation
2507
2503
  }) {
2508
2504
  const result = (0, import_genre_tree27.useSong)(uuid, getBackendBaseUrl);
2509
2505
  const panel = { expanded, onExpandedChange, onClose };
@@ -2547,8 +2543,10 @@ function useSongPanel({
2547
2543
  getBackendBaseUrl,
2548
2544
  shareUrl: shareUrl ?? void 0,
2549
2545
  renderArtistLink,
2550
- genrePath: song.genre ? getGenrePath(song.genre) : [],
2551
- onSelectGenre
2546
+ ...navigation.getGenrePath ? {
2547
+ genrePath: song.genre ? navigation.getGenrePath(song.genre) : [],
2548
+ onSelectGenrePlaylist: navigation.onSelectGenrePlaylist
2549
+ } : { onSelectGenre: navigation.onSelectGenre }
2552
2550
  }
2553
2551
  )
2554
2552
  };
@@ -2556,6 +2554,37 @@ function useSongPanel({
2556
2554
  }
2557
2555
  }
2558
2556
 
2557
+ // src/genre-tree/useEntityPanel.tsx
2558
+ function useEntityPanel({
2559
+ scope,
2560
+ getBackendBaseUrl,
2561
+ getArtistBackendBaseUrl,
2562
+ getShareUrl,
2563
+ renderArtistLink,
2564
+ renderSongLink,
2565
+ song,
2566
+ artist,
2567
+ ...navigation
2568
+ }) {
2569
+ const songPanel = useSongPanel({
2570
+ ...song,
2571
+ scope,
2572
+ getBackendBaseUrl,
2573
+ getShareUrl,
2574
+ renderArtistLink,
2575
+ ...navigation
2576
+ });
2577
+ const artistPanel = useArtistPanel({
2578
+ ...artist,
2579
+ scope,
2580
+ getBackendBaseUrl: getArtistBackendBaseUrl ?? getBackendBaseUrl,
2581
+ getShareUrl,
2582
+ renderArtistLink,
2583
+ renderSongLink
2584
+ });
2585
+ return songPanel ?? artistPanel;
2586
+ }
2587
+
2559
2588
  // src/genre-tree/SizeMetricToggle.tsx
2560
2589
  var import_md = require("react-icons/md");
2561
2590
  var import_ui16 = require("@behindthemusictree/ui");
@@ -2738,20 +2767,6 @@ function GenreTreeView({
2738
2767
  const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react18.useState)(null);
2739
2768
  const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
2740
2769
  const songBaseUrl = getBackendBaseUrl;
2741
- const artistPanel = useArtistPanel({
2742
- uuid: artistUuid,
2743
- scope,
2744
- getBackendBaseUrl: artistBaseUrl,
2745
- getShareUrl: getShareUrlRef.current,
2746
- renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
2747
- expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
2748
- onExpandedChange: (on) => {
2749
- if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
2750
- onArtistExpandedChange?.(on);
2751
- },
2752
- renderSongLink: resolvedRenderSongLink,
2753
- onClose: () => changeArtist(null)
2754
- });
2755
2770
  const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
2756
2771
  const getGenrePath = (genre) => {
2757
2772
  const path = [];
@@ -2763,27 +2778,38 @@ function GenreTreeView({
2763
2778
  }
2764
2779
  return path;
2765
2780
  };
2766
- const songPanel = useSongPanel({
2767
- uuid: songUuid,
2781
+ const entityPanel = useEntityPanel({
2768
2782
  scope,
2769
2783
  getBackendBaseUrl: songBaseUrl,
2784
+ getArtistBackendBaseUrl: artistBaseUrl,
2770
2785
  getShareUrl: getShareUrlRef.current,
2771
2786
  renderArtistLink: resolvedRenderArtistLink,
2787
+ renderSongLink: resolvedRenderSongLink,
2788
+ song: {
2789
+ uuid: songUuid,
2790
+ expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),
2791
+ onExpandedChange: (on) => {
2792
+ if (controlledSongExpanded === void 0) setExpandedSongUuid(on ? songUuid : null);
2793
+ onSongExpandedChange?.(on);
2794
+ },
2795
+ onClose: () => changeSong(null)
2796
+ },
2797
+ artist: {
2798
+ uuid: artistUuid,
2799
+ expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
2800
+ onExpandedChange: (on) => {
2801
+ if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
2802
+ onArtistExpandedChange?.(on);
2803
+ },
2804
+ onClose: () => changeArtist(null)
2805
+ },
2772
2806
  getGenrePath,
2773
- onSelectGenre: (genrePlaylist2) => {
2807
+ onSelectGenrePlaylist: (genrePlaylist2) => {
2774
2808
  changeSong(null);
2775
2809
  selectGenrePlaylist(genrePlaylist2);
2776
- },
2777
- expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),
2778
- onExpandedChange: (on) => {
2779
- if (controlledSongExpanded === void 0) setExpandedSongUuid(on ? songUuid : null);
2780
- onSongExpandedChange?.(on);
2781
- },
2782
- onClose: () => changeSong(null)
2810
+ }
2783
2811
  });
2784
- const builtInSongPanel = overlayPanel || selectedGenreUuid !== null ? void 0 : songPanel;
2785
- const builtInArtistPanel = overlayPanel || selectedGenreUuid !== null || builtInSongPanel ? void 0 : artistPanel;
2786
- const builtInPanel = builtInSongPanel ?? builtInArtistPanel;
2812
+ const builtInPanel = overlayPanel || selectedGenreUuid !== null ? void 0 : entityPanel;
2787
2813
  const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react18.useState)(false);
2788
2814
  const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react18.useState)(false);
2789
2815
  const isCollapsed = collapsed ?? uncontrolledCollapsed;
@@ -3652,8 +3678,72 @@ function Rating({ rating, handleChange }) {
3652
3678
  ) })
3653
3679
  ] }, i)) });
3654
3680
  }
3681
+
3682
+ // src/genre-tree/EntityDetailPanel.tsx
3683
+ var import_react21 = require("react");
3684
+ var import_ui19 = require("@behindthemusictree/ui");
3685
+ var import_jsx_runtime45 = require("react/jsx-runtime");
3686
+ function EntityDetailPanel({
3687
+ scope,
3688
+ getBackendBaseUrl,
3689
+ getArtistBackendBaseUrl,
3690
+ getShareUrl,
3691
+ songUuid,
3692
+ onSongUuidChange,
3693
+ artistUuid,
3694
+ onArtistUuidChange,
3695
+ renderArtistLink,
3696
+ renderSongLink,
3697
+ collapsed,
3698
+ edgeTab,
3699
+ ...navigation
3700
+ }) {
3701
+ const [expandedSongUuid, setExpandedSongUuid] = (0, import_react21.useState)(null);
3702
+ const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react21.useState)(null);
3703
+ const panel = useEntityPanel({
3704
+ scope,
3705
+ getBackendBaseUrl,
3706
+ getArtistBackendBaseUrl,
3707
+ getShareUrl,
3708
+ renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
3709
+ renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
3710
+ song: {
3711
+ uuid: songUuid,
3712
+ expanded: songUuid !== null && expandedSongUuid === songUuid,
3713
+ onExpandedChange: (on) => setExpandedSongUuid(on ? songUuid : null),
3714
+ onClose: () => onSongUuidChange(null)
3715
+ },
3716
+ artist: {
3717
+ uuid: artistUuid,
3718
+ expanded: artistUuid !== null && expandedArtistUuid === artistUuid,
3719
+ onExpandedChange: (on) => setExpandedArtistUuid(on ? artistUuid : null),
3720
+ onClose: () => onArtistUuidChange(null)
3721
+ },
3722
+ ...navigation
3723
+ });
3724
+ if (!panel) return null;
3725
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3726
+ import_ui19.DetailPanel,
3727
+ {
3728
+ side: "left",
3729
+ title: panel.title,
3730
+ titleInSearch: true,
3731
+ onClose: panel.onClose,
3732
+ collapsed,
3733
+ expanded: panel.expanded,
3734
+ onExpandedChange: panel.onExpandedChange,
3735
+ aside: panel.extraContent,
3736
+ edgeTab,
3737
+ children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
3738
+ panel.content,
3739
+ panel.extraContent
3740
+ ] }) : panel.content
3741
+ }
3742
+ );
3743
+ }
3655
3744
  // Annotate the CommonJS export names for ESM import in node:
3656
3745
  0 && (module.exports = {
3746
+ EntityDetailPanel,
3657
3747
  GenreDetailPanel,
3658
3748
  GenreInfoPanelBody,
3659
3749
  GenreNodeActionBand,
@@ -3673,6 +3763,7 @@ function Rating({ rating, handleChange }) {
3673
3763
  TrackPositionPlayPause,
3674
3764
  searchStatus,
3675
3765
  useArtistSearchGroup,
3766
+ useEntityPanel,
3676
3767
  useGenrePlaylistPlayback,
3677
3768
  useGenreRemoteSearchGroup,
3678
3769
  useSongSearchGroup