@behindthemusictree/app-kit-ui 40.0.0 → 40.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.
@@ -23,7 +23,7 @@ import {
23
23
  useGenrePlaylistPlayback,
24
24
  useGenreRemoteSearchGroup,
25
25
  useSongSearchGroup
26
- } from "../chunk-I2TEOHVG.js";
26
+ } from "../chunk-DPYUE6WD.js";
27
27
  import "../chunk-2GH7CSCE.js";
28
28
  export {
29
29
  EntityDetailPanel,
package/dist/index.cjs CHANGED
@@ -591,8 +591,8 @@ function AuthCallbackHandler({ renderStatus, ...options }) {
591
591
  // src/genre-tree/GenreTreeView.tsx
592
592
  var import_react19 = require("react");
593
593
  var import_react_query3 = require("@tanstack/react-query");
594
+ var import_lucide_react17 = require("lucide-react");
594
595
  var import_lucide_react18 = require("lucide-react");
595
- var import_lucide_react19 = require("lucide-react");
596
596
  var import_ui24 = require("@behindthemusictree/ui");
597
597
  var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
598
598
  var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
@@ -626,6 +626,21 @@ function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
626
626
  }));
627
627
  }
628
628
 
629
+ // src/genre-tree/playlist-tree/toGenreNodeStyles.ts
630
+ function toGenreNodeStyles(relations, genrePlaylists) {
631
+ const styles = /* @__PURE__ */ new Map();
632
+ if (!relations) return styles;
633
+ const genreUuidByPlaylistUuid = new Map(
634
+ genrePlaylists.flatMap((genrePlaylist) => genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid]] : [])
635
+ );
636
+ const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];
637
+ for (const entry of drawn) {
638
+ const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);
639
+ if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });
640
+ }
641
+ return styles;
642
+ }
643
+
629
644
  // src/genre-tree/playlist-tree/TreePerRoot.tsx
630
645
  var import_genre_tree3 = require("@behindthemusictree/app-kit/genre-tree");
631
646
  var import_react4 = require("react");
@@ -2043,7 +2058,7 @@ function useGenreDetailContent({
2043
2058
  trailing,
2044
2059
  genrePlaylist: hostPlaylist,
2045
2060
  expanded,
2046
- treeRelations
2061
+ treeStyles
2047
2062
  }) {
2048
2063
  const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
2049
2064
  const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
@@ -2051,19 +2066,12 @@ function useGenreDetailContent({
2051
2066
  const view = (0, import_react15.useMemo)(() => {
2052
2067
  if (!detail) return null;
2053
2068
  const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
2054
- const treeStyles = /* @__PURE__ */ new Map();
2055
- if (treeRelations) {
2056
- const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
2057
- for (const entry of drawn) {
2058
- if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
2059
- }
2060
- }
2061
2069
  const relative = (genre, parentId) => ({
2062
2070
  node: toNode(genre, parentId),
2063
- ...treeStyles.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
2071
+ ...treeStyles?.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
2064
2072
  });
2065
2073
  const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
2066
- const own = treeStyles.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
2074
+ const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
2067
2075
  return {
2068
2076
  node: {
2069
2077
  id: detail.uuid,
@@ -2080,7 +2088,7 @@ function useGenreDetailContent({
2080
2088
  ({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
2081
2089
  )
2082
2090
  };
2083
- }, [detail, scope, treeRelations]);
2091
+ }, [detail, scope, treeStyles]);
2084
2092
  if (isError) return {
2085
2093
  name: null,
2086
2094
  title: "Genre unavailable",
@@ -2438,7 +2446,6 @@ function ArtistDiscography({ albums }) {
2438
2446
  // src/genre-tree/artist/ArtistSongs.tsx
2439
2447
  var import_react17 = require("react");
2440
2448
  var import_react_query2 = require("@tanstack/react-query");
2441
- var import_lucide_react16 = require("lucide-react");
2442
2449
  var import_ui19 = require("@behindthemusictree/ui");
2443
2450
  var import_player11 = require("@behindthemusictree/app-kit/player");
2444
2451
  var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
@@ -2603,34 +2610,20 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
2603
2610
  void play(song.uuid);
2604
2611
  };
2605
2612
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_ui19.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_ui19.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
2606
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
2607
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
2608
- "button",
2609
- {
2610
- type: "button",
2611
- onClick: () => void play(),
2612
- className: "flex w-fit items-center gap-1.5 px-3 py-1 text-caption font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
2613
- children: [
2614
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react16.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2615
- "Play all"
2616
- ]
2617
- }
2618
- ),
2619
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2620
- "button",
2621
- {
2622
- type: "button",
2623
- "aria-pressed": ordering === sort.ordering,
2624
- onClick: () => {
2625
- setOrdering(sort.ordering);
2626
- setPage(1);
2627
- },
2628
- className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
2629
- children: sort.label
2613
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2614
+ "button",
2615
+ {
2616
+ type: "button",
2617
+ "aria-pressed": ordering === sort.ordering,
2618
+ onClick: () => {
2619
+ setOrdering(sort.ordering);
2620
+ setPage(1);
2630
2621
  },
2631
- sort.ordering
2632
- )) })
2633
- ] }),
2622
+ className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
2623
+ children: sort.label
2624
+ },
2625
+ sort.ordering
2626
+ )) }) }),
2634
2627
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2635
2628
  TrackItem,
2636
2629
  {
@@ -2728,7 +2721,7 @@ var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
2728
2721
 
2729
2722
  // src/genre-tree/song/SongPanelContent.tsx
2730
2723
  var import_react18 = require("react");
2731
- var import_lucide_react17 = require("lucide-react");
2724
+ var import_lucide_react16 = require("lucide-react");
2732
2725
  var import_ui21 = require("@behindthemusictree/ui");
2733
2726
  var import_player12 = require("@behindthemusictree/app-kit/player");
2734
2727
  var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
@@ -2821,7 +2814,7 @@ function SongPanelContent(props) {
2821
2814
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2822
2815
  import_ui21.ActionButton,
2823
2816
  {
2824
- icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react17.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react17.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2817
+ icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
2825
2818
  label: isPlaying ? "Pause" : "Play",
2826
2819
  disabled: !!unplayableReason,
2827
2820
  title: unplayableReason ?? void 0,
@@ -3193,6 +3186,7 @@ function GenreTreeView({
3193
3186
  !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
3194
3187
  resolveStyle
3195
3188
  );
3189
+ const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
3196
3190
  const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: selectedGenreUuid, previous: null });
3197
3191
  if (selectionHistory.current !== selectedGenreUuid) {
3198
3192
  setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
@@ -3238,7 +3232,7 @@ function GenreTreeView({
3238
3232
  selectGenre(uuid);
3239
3233
  },
3240
3234
  expanded: isExpanded,
3241
- treeRelations: relations,
3235
+ treeStyles,
3242
3236
  playback,
3243
3237
  genrePlaylist: selectedGenrePlaylist,
3244
3238
  band: {
@@ -3316,7 +3310,7 @@ function GenreTreeView({
3316
3310
  "aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
3317
3311
  style: activePanel.headerAccent && { color: "inherit" },
3318
3312
  onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
3319
- children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react19.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react19.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
3313
+ children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react18.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react18.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
3320
3314
  }
3321
3315
  ) : null;
3322
3316
  const renderArtistFilter = () => {
@@ -3416,7 +3410,7 @@ function GenreTreeView({
3416
3410
  !isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3417
3411
  import_ui24.IconTextButton,
3418
3412
  {
3419
- icon: import_lucide_react18.Plus,
3413
+ icon: import_lucide_react17.Plus,
3420
3414
  text: "Add root",
3421
3415
  onClick: () => handleGenreCreationAction(null)
3422
3416
  }
@@ -3593,7 +3587,7 @@ var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
3593
3587
 
3594
3588
  // src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
3595
3589
  var import_react20 = require("react");
3596
- var import_lucide_react20 = require("lucide-react");
3590
+ var import_lucide_react19 = require("lucide-react");
3597
3591
  var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
3598
3592
  var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
3599
3593
  var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
@@ -3726,7 +3720,7 @@ function TrackListSidebar({
3726
3720
  "aria-expanded": !isCollapsed,
3727
3721
  className: `ml-2 flex h-8 w-8 shrink-0 items-center justify-center rounded-md hover:bg-[var(--color-surface-muted)] ${isCollapsed ? "text-[var(--color-text-muted)]" : "text-white"}`,
3728
3722
  onClick: isCollapsed ? onExpand : onMinimize,
3729
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react20.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
3723
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react19.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
3730
3724
  }
3731
3725
  )
3732
3726
  ] }),
@@ -3768,7 +3762,7 @@ var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
3768
3762
  var import_ui25 = require("@behindthemusictree/ui");
3769
3763
 
3770
3764
  // src/genre-tree/PlayerControls.tsx
3771
- var import_lucide_react21 = require("lucide-react");
3765
+ var import_lucide_react20 = require("lucide-react");
3772
3766
  var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
3773
3767
  var import_player13 = require("@behindthemusictree/app-kit/player");
3774
3768
  var import_jsx_runtime53 = require("react/jsx-runtime");
@@ -3825,7 +3819,7 @@ function PlayerControls() {
3825
3819
  disabled: !isReady || !hasPreviousTrack,
3826
3820
  onClick: playPreviousTrack,
3827
3821
  className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40",
3828
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
3822
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
3829
3823
  }
3830
3824
  ),
3831
3825
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
@@ -3837,7 +3831,7 @@ function PlayerControls() {
3837
3831
  disabled: !isReady,
3838
3832
  onClick: handlePlayPauseAction,
3839
3833
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-zinc-950 hover:bg-zinc-200 disabled:cursor-not-allowed disabled:opacity-40",
3840
- children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
3834
+ children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
3841
3835
  }
3842
3836
  ),
3843
3837
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
@@ -3849,12 +3843,12 @@ function PlayerControls() {
3849
3843
  disabled: !isReady || !hasNextTrack,
3850
3844
  onClick: playNextTrack,
3851
3845
  className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40",
3852
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
3846
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
3853
3847
  }
3854
3848
  )
3855
3849
  ] }),
3856
3850
  /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("label", { className: "col-start-3 flex w-[4.2rem] shrink-0 items-center gap-[0.35rem] justify-self-end text-zinc-400 sm:w-[4.9rem]", children: [
3857
- volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
3851
+ volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
3858
3852
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "sr-only", children: "Volume" }),
3859
3853
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3860
3854
  "input",