@behindthemusictree/app-kit-ui 35.0.0 → 37.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.
- package/dist/{chunk-YC3WBUVO.js → chunk-FTYMRCJS.js} +46 -30
- package/dist/chunk-FTYMRCJS.js.map +1 -0
- package/dist/genre-tree/index.cjs +43 -27
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +9 -4
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +43 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-YC3WBUVO.js.map +0 -1
|
@@ -722,6 +722,7 @@ function SearchBox({
|
|
|
722
722
|
groups,
|
|
723
723
|
onPicked,
|
|
724
724
|
onClear,
|
|
725
|
+
clearLabel,
|
|
725
726
|
leading,
|
|
726
727
|
className: className2,
|
|
727
728
|
onFocus
|
|
@@ -753,6 +754,7 @@ function SearchBox({
|
|
|
753
754
|
status,
|
|
754
755
|
loading,
|
|
755
756
|
onClear,
|
|
757
|
+
clearLabel,
|
|
756
758
|
leading,
|
|
757
759
|
inputClassName: "focus-visible:ring-0"
|
|
758
760
|
}
|
|
@@ -848,6 +850,8 @@ function GenreSearch({
|
|
|
848
850
|
onSelect,
|
|
849
851
|
selectedName = null,
|
|
850
852
|
onClear,
|
|
853
|
+
showClear,
|
|
854
|
+
clearLabel,
|
|
851
855
|
onPrevious,
|
|
852
856
|
placeholder,
|
|
853
857
|
onQueryChange,
|
|
@@ -895,7 +899,8 @@ function GenreSearch({
|
|
|
895
899
|
if (groupKey !== "genres") setQuery("");
|
|
896
900
|
onQueryChange?.("");
|
|
897
901
|
},
|
|
898
|
-
|
|
902
|
+
clearLabel,
|
|
903
|
+
onClear: showClear ?? canClear ? () => {
|
|
899
904
|
clear();
|
|
900
905
|
onQueryChange?.("");
|
|
901
906
|
} : void 0,
|
|
@@ -1417,7 +1422,7 @@ function GenrePlaylistTracks({
|
|
|
1417
1422
|
const trackNoun = (0, import_track_noun.useTrackNoun)();
|
|
1418
1423
|
const uuid = genrePlaylist?.uuid;
|
|
1419
1424
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
1420
|
-
const {
|
|
1425
|
+
const { fetchBound } = (0, import_transport3.usePlaybackFetch)(getBackendBaseUrl);
|
|
1421
1426
|
const playback = (0, import_transport3.usePlaybackContext)();
|
|
1422
1427
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
1423
1428
|
queryKey: [...scope === "me" ? uuid ? import_genre_tree12.genrePlaylistQueryKeys.me.tracks(uuid) : ["missing-personal-genre-playlist", genreUuid] : artist ? [...import_genre_tree13.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), "artist", artist.uuid] : import_genre_tree13.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), ...playback.key ? [playback.key] : []],
|
|
@@ -1426,7 +1431,7 @@ function GenrePlaylistTracks({
|
|
|
1426
1431
|
if (!uuid) throw new Error("Personal genre has no playlist");
|
|
1427
1432
|
return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));
|
|
1428
1433
|
}
|
|
1429
|
-
const response = await
|
|
1434
|
+
const response = await fetchBound(
|
|
1430
1435
|
import_genre_tree13.libraryEndpoints.reference.songs.list(),
|
|
1431
1436
|
true,
|
|
1432
1437
|
false,
|
|
@@ -1438,7 +1443,9 @@ function GenrePlaylistTracks({
|
|
|
1438
1443
|
},
|
|
1439
1444
|
initialPageParam: scope === "me" ? 1 : "",
|
|
1440
1445
|
getNextPageParam: (lastPage) => lastPage.nextPage ?? void 0,
|
|
1441
|
-
enabled: playback.ready && (scope !== "me" || uuid !== void 0 && sessionRestored && !!session?.accessToken)
|
|
1446
|
+
enabled: playback.ready && (scope !== "me" || uuid !== void 0 && sessionRestored && !!session?.accessToken),
|
|
1447
|
+
retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === "AbortError",
|
|
1448
|
+
retryDelay: 0
|
|
1442
1449
|
});
|
|
1443
1450
|
const [sentinel, setSentinel] = (0, import_react12.useState)(null);
|
|
1444
1451
|
(0, import_react12.useEffect)(() => {
|
|
@@ -1757,10 +1764,12 @@ function useGenreDetailContent({
|
|
|
1757
1764
|
};
|
|
1758
1765
|
}, [detail, scope]);
|
|
1759
1766
|
if (isError) return {
|
|
1767
|
+
name: null,
|
|
1760
1768
|
title: "Genre unavailable",
|
|
1761
1769
|
content: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1762
1770
|
};
|
|
1763
1771
|
if (isPending || !detail || !view) return {
|
|
1772
|
+
name: null,
|
|
1764
1773
|
title: "Loading genre\u2026",
|
|
1765
1774
|
content: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1766
1775
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ui7.Skeleton, { className: "h-6 w-2/3" }),
|
|
@@ -1782,6 +1791,7 @@ function useGenreDetailContent({
|
|
|
1782
1791
|
);
|
|
1783
1792
|
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1784
1793
|
return {
|
|
1794
|
+
name: detail.name,
|
|
1785
1795
|
title: detail.name,
|
|
1786
1796
|
headerAccent: { background: view.fill, color: import_genre_tree_view4.ACCENT_TEXT_COLOR },
|
|
1787
1797
|
aside: expanded ? ancestors : void 0,
|
|
@@ -1823,7 +1833,7 @@ function GenreDetailPanel({
|
|
|
1823
1833
|
onExpandedChange,
|
|
1824
1834
|
edgeTab,
|
|
1825
1835
|
extras,
|
|
1826
|
-
|
|
1836
|
+
titleInSearch
|
|
1827
1837
|
}) {
|
|
1828
1838
|
const panel = useGenreDetailContent({
|
|
1829
1839
|
genreUuid,
|
|
@@ -1846,7 +1856,7 @@ function GenreDetailPanel({
|
|
|
1846
1856
|
onExpandedChange,
|
|
1847
1857
|
edgeTab,
|
|
1848
1858
|
aside: panel.aside,
|
|
1849
|
-
|
|
1859
|
+
titleInSearch,
|
|
1850
1860
|
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ui7.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react8.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react8.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1851
1861
|
children: panel.content
|
|
1852
1862
|
}
|
|
@@ -2214,12 +2224,12 @@ var SORTS = [
|
|
|
2214
2224
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
2215
2225
|
const [page, setPage] = (0, import_react16.useState)(1);
|
|
2216
2226
|
const [ordering, setOrdering] = (0, import_react16.useState)("title");
|
|
2217
|
-
const { fetch } = (0, import_transport7.useFetchWrapper)(getBackendBaseUrl);
|
|
2218
2227
|
const { playNewTrackListFromArtist } = (0, import_genre_tree24.useTrackList)();
|
|
2219
2228
|
const { playerTrackObject } = (0, import_player10.usePlayer)();
|
|
2220
|
-
const { data, isPending, isError } = (0, import_transport7.
|
|
2229
|
+
const { data, isPending, isError } = (0, import_transport7.usePlaybackQuery)({
|
|
2230
|
+
getBackendBaseUrl,
|
|
2221
2231
|
queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
|
|
2222
|
-
queryFn: () =>
|
|
2232
|
+
queryFn: (fetchBound) => fetchBound(import_genre_tree24.libraryEndpoints.reference.songs.list(), true, false, void 0, {
|
|
2223
2233
|
artist: artist.uuid,
|
|
2224
2234
|
ordering,
|
|
2225
2235
|
page
|
|
@@ -2657,6 +2667,8 @@ function GenreTreeView({
|
|
|
2657
2667
|
};
|
|
2658
2668
|
const {
|
|
2659
2669
|
isLoading,
|
|
2670
|
+
isError,
|
|
2671
|
+
refetch,
|
|
2660
2672
|
isFetching: isTreeFetching,
|
|
2661
2673
|
genrePlaylistByNodeId,
|
|
2662
2674
|
visibleGenrePlaylists,
|
|
@@ -2789,7 +2801,7 @@ function GenreTreeView({
|
|
|
2789
2801
|
}, [selectedGenreUuid, artistUuid, songUuid]);
|
|
2790
2802
|
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react18.useState)(false);
|
|
2791
2803
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
2792
|
-
const isTreeReady = !isLoading && (!usesHandoff || isWheelRevealed);
|
|
2804
|
+
const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
|
|
2793
2805
|
const [resolveStyle, setResolveStyle] = (0, import_react18.useState)(null);
|
|
2794
2806
|
const handleNodeStyleResolverChange = (0, import_react18.useCallback)(
|
|
2795
2807
|
(resolver) => setResolveStyle(() => resolver),
|
|
@@ -2820,7 +2832,6 @@ function GenreTreeView({
|
|
|
2820
2832
|
if (node !== null && songUuid !== null) changeSong(null);
|
|
2821
2833
|
selectNode(node);
|
|
2822
2834
|
};
|
|
2823
|
-
const handleGenreSearchClear = clearSelection;
|
|
2824
2835
|
const handleGenreSearchSelect = (genrePlaylist2) => {
|
|
2825
2836
|
reopenPanel();
|
|
2826
2837
|
if (songUuid !== null) changeSong(null);
|
|
@@ -2903,7 +2914,7 @@ function GenreTreeView({
|
|
|
2903
2914
|
expanded: overlayPanel.expanded ?? false,
|
|
2904
2915
|
onExpandedChange: overlayPanel.onExpandedChange,
|
|
2905
2916
|
onClose: overlayPanel.onClose,
|
|
2906
|
-
|
|
2917
|
+
titleInSearch: false
|
|
2907
2918
|
};
|
|
2908
2919
|
} else if (selectedGenreUuid) {
|
|
2909
2920
|
activePanel = {
|
|
@@ -2913,7 +2924,7 @@ function GenreTreeView({
|
|
|
2913
2924
|
expanded: isExpanded,
|
|
2914
2925
|
onExpandedChange: changeExpanded,
|
|
2915
2926
|
onClose: clearSelection,
|
|
2916
|
-
|
|
2927
|
+
titleInSearch: true,
|
|
2917
2928
|
headerAccent: relations ? { background: relations.fill, color: relations.textColor } : genreContent.headerAccent
|
|
2918
2929
|
};
|
|
2919
2930
|
} else if (builtInPanel) {
|
|
@@ -2924,7 +2935,7 @@ function GenreTreeView({
|
|
|
2924
2935
|
expanded: builtInPanel.expanded,
|
|
2925
2936
|
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2926
2937
|
onClose: builtInPanel.onClose,
|
|
2927
|
-
|
|
2938
|
+
titleInSearch: true
|
|
2928
2939
|
};
|
|
2929
2940
|
}
|
|
2930
2941
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
@@ -2969,7 +2980,7 @@ function GenreTreeView({
|
|
|
2969
2980
|
] });
|
|
2970
2981
|
};
|
|
2971
2982
|
const actions = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
2972
|
-
!isLoading && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2983
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2973
2984
|
GenreTreeSearch,
|
|
2974
2985
|
{
|
|
2975
2986
|
artistBaseUrl,
|
|
@@ -2992,17 +3003,19 @@ function GenreTreeView({
|
|
|
2992
3003
|
if (songUuid) changeSong(null);
|
|
2993
3004
|
selectGenre(uuid);
|
|
2994
3005
|
},
|
|
2995
|
-
selectedName:
|
|
2996
|
-
onClear:
|
|
3006
|
+
selectedName: selectedGenreUuid ? genreContent.name : typeof builtInPanel?.title === "string" ? builtInPanel.title : null,
|
|
3007
|
+
onClear: activePanel?.onClose,
|
|
3008
|
+
showClear: activePanel?.titleInSearch ?? false,
|
|
3009
|
+
clearLabel: "Close panel",
|
|
2997
3010
|
onPrevious: handlePrevious,
|
|
2998
3011
|
onQueryChange: onSearchQueryChange,
|
|
2999
3012
|
onFocus: onSearchFocus,
|
|
3000
3013
|
extraGroups: extraSearchGroups
|
|
3001
3014
|
}
|
|
3002
3015
|
),
|
|
3003
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3016
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3004
3017
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "contents max-md:flex max-md:w-full max-md:items-center max-md:gap-2 max-md:overflow-x-auto max-md:[scrollbar-width:none] max-md:[&>*]:shrink-0", children: [
|
|
3005
|
-
!isLoading && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3018
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3006
3019
|
import_ui17.SegmentedControl,
|
|
3007
3020
|
{
|
|
3008
3021
|
"aria-label": "Tree view mode",
|
|
@@ -3016,7 +3029,7 @@ function GenreTreeView({
|
|
|
3016
3029
|
]
|
|
3017
3030
|
}
|
|
3018
3031
|
),
|
|
3019
|
-
!isLoading && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3032
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3020
3033
|
"div",
|
|
3021
3034
|
{
|
|
3022
3035
|
className: "flex items-center gap-1",
|
|
@@ -3033,7 +3046,7 @@ function GenreTreeView({
|
|
|
3033
3046
|
)
|
|
3034
3047
|
}
|
|
3035
3048
|
),
|
|
3036
|
-
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3049
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3037
3050
|
import_ui17.IconTextButton,
|
|
3038
3051
|
{
|
|
3039
3052
|
icon: import_lucide_react12.Plus,
|
|
@@ -3056,7 +3069,7 @@ function GenreTreeView({
|
|
|
3056
3069
|
children: actions
|
|
3057
3070
|
}
|
|
3058
3071
|
),
|
|
3059
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3072
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3060
3073
|
"div",
|
|
3061
3074
|
{
|
|
3062
3075
|
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))]" : "top-5"}`,
|
|
@@ -3064,8 +3077,12 @@ function GenreTreeView({
|
|
|
3064
3077
|
}
|
|
3065
3078
|
),
|
|
3066
3079
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3067
|
-
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3068
|
-
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) :
|
|
3080
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3081
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3082
|
+
"Couldn't load the genre tree.",
|
|
3083
|
+
" ",
|
|
3084
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3085
|
+
] }) : viewMode === "wheel" ? (
|
|
3069
3086
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3070
3087
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3071
3088
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
@@ -3179,8 +3196,7 @@ function GenreTreeView({
|
|
|
3179
3196
|
ref: panelRef,
|
|
3180
3197
|
side: "left",
|
|
3181
3198
|
title: activePanel?.title ?? "",
|
|
3182
|
-
|
|
3183
|
-
hideClose: activePanel?.compact,
|
|
3199
|
+
titleInSearch: activePanel?.titleInSearch,
|
|
3184
3200
|
headerAccent: activePanel?.headerAccent,
|
|
3185
3201
|
headerActions: expandButton,
|
|
3186
3202
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3189,7 +3205,7 @@ function GenreTreeView({
|
|
|
3189
3205
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3190
3206
|
aside: activePanel?.aside,
|
|
3191
3207
|
edgeTab: detailTab,
|
|
3192
|
-
headerClassName: "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]",
|
|
3208
|
+
headerClassName: activePanel?.titleInSearch ? void 0 : "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]",
|
|
3193
3209
|
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
3194
3210
|
activePanel.content,
|
|
3195
3211
|
activePanel.aside
|