@behindthemusictree/app-kit-ui 24.0.1 → 28.0.2

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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { AuthErrorPopup, AuthPopup, BasePopup, BasePopupProps, InternalErrorPopup, NetworkErrorPopup, PopupButtons, PopupTitle, SpotifyAuthErrorPopup, TrackUploadPopup } from './popup/index.js';
1
+ export { AuthErrorPopup, AuthPopup, BasePopup, BasePopupProps, InternalErrorPopup, NetworkErrorPopup, PopupButtons, PopupTitle, SpotifyAuthErrorPopup, Toast, ToastProps, TrackUploadPopup } from './popup/index.js';
2
2
  export { AuthCallbackHandler, AuthCallbackHandlerProps } from './auth/index.js';
3
- export { ArtistSearchProps, GenreDetailSlots, GenreFocusProps, GenrePlaylistTracksSlots, GenrePlaylistTreePerRoot, GenrePlaylistTreePerRootProps, GenreSearch, GenreSearchExtraResults, GenreSearchProps, GenreTreeView, GenreTreeViewProps, InfoPanelCurationProps, PanelEdgeTab, PanelEdgeTabAction, PanelEdgeTabProps, PlayerPanel, PlayerPanelProps, Rating, RatingProps, TrackItem, TrackItemProps, TrackListSidebar, TrackListSidebarProps, TrackPositionPlayPause, TrackPositionPlayPauseProps } from './genre-tree/index.js';
3
+ export { ArtistSearchProps, GenreDetailSlots, GenreFocusProps, GenrePlaylistTracksSlots, GenrePlaylistTreePerRoot, GenrePlaylistTreePerRootProps, GenreSearch, GenreSearchExtraResults, GenreSearchProps, GenreTreeShareTarget, GenreTreeView, GenreTreeViewProps, GetGenreTreeShareUrl, InfoPanelCurationProps, PanelEdgeTab, PanelEdgeTabAction, PanelEdgeTabProps, ParentChange, PlayerPanel, PlayerPanelProps, Rating, RatingProps, TrackItem, TrackItemProps, TrackListSidebar, TrackListSidebarProps, TrackPositionPlayPause, TrackPositionPlayPauseProps } from './genre-tree/index.js';
4
4
  export { ControlsOrientation, FocusChangeReason, GenreTreeAction, GenreTreeOutlineSkeleton, GenreTreeSkeleton, GenreTreeViewMode, GenreTreeViewSkeleton, GenreTreeViewSkeletonProps, GenreTreeViewport, GenreTreeWheelSkeleton } from '@behindthemusictree/genre-tree-view';
5
5
  import 'react';
6
6
  import 'lucide-react';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  NetworkErrorPopup,
5
5
  SpotifyAuthErrorPopup,
6
6
  TrackUploadPopup
7
- } from "./chunk-ZLCRD7OK.js";
7
+ } from "./chunk-XUC4UJDQ.js";
8
8
  import {
9
9
  AuthCallbackHandler
10
10
  } from "./chunk-MMJCB3CJ.js";
@@ -22,13 +22,14 @@ import {
22
22
  TrackItem,
23
23
  TrackListSidebar,
24
24
  TrackPositionPlayPause
25
- } from "./chunk-BPCFNBFO.js";
25
+ } from "./chunk-5PQWJRDZ.js";
26
26
  import {
27
27
  BasePopup,
28
28
  InternalErrorPopup,
29
29
  PopupButtons,
30
- PopupTitle
31
- } from "./chunk-VDXUW7PP.js";
30
+ PopupTitle,
31
+ Toast
32
+ } from "./chunk-DKQQLLMY.js";
32
33
  export {
33
34
  AuthCallbackHandler,
34
35
  AuthErrorPopup,
@@ -49,6 +50,7 @@ export {
49
50
  PopupTitle,
50
51
  Rating,
51
52
  SpotifyAuthErrorPopup,
53
+ Toast,
52
54
  TrackItem,
53
55
  TrackListSidebar,
54
56
  TrackPositionPlayPause,
@@ -28,6 +28,7 @@ __export(popup_exports, {
28
28
  PopupButtons: () => PopupButtons,
29
29
  PopupTitle: () => PopupTitle,
30
30
  SpotifyAuthErrorPopup: () => SpotifyAuthErrorPopup,
31
+ Toast: () => Toast,
31
32
  TrackUploadPopup: () => TrackUploadPopup
32
33
  });
33
34
  module.exports = __toCommonJS(popup_exports);
@@ -36,13 +37,29 @@ module.exports = __toCommonJS(popup_exports);
36
37
  var import_lucide_react = require("lucide-react");
37
38
  var import_ui = require("@behindthemusictree/ui");
38
39
  var import_jsx_runtime = require("react/jsx-runtime");
39
- function PopupTitle({ title, onClose, isDismissable, icon: Icon }) {
40
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "popup-title flex items-center justify-between bg-black p-4 rounded-t-lg", children: [
40
+ function PopupTitle({
41
+ title,
42
+ onClose,
43
+ isDismissable,
44
+ icon: Icon,
45
+ className = "",
46
+ titleClassName = "",
47
+ closeButtonClassName = ""
48
+ }) {
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `popup-title flex items-center justify-between bg-black p-4 rounded-t-lg ${className}`, children: [
41
50
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
42
51
  Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-5 w-5 text-white" }),
43
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { id: "popup-title", className: "text-white font-semibold", children: title })
52
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { id: "popup-title", className: `text-white font-semibold ${titleClassName}`, children: title })
44
53
  ] }),
45
- isDismissable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.Button, { onClick: onClose, className: "h-8 w-8 text-white hover:text-white/80", "aria-label": "Close popup", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-4 w-4" }) })
54
+ isDismissable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
55
+ import_ui.Button,
56
+ {
57
+ onClick: onClose,
58
+ className: `h-8 w-8 text-white hover:text-white/80 ${closeButtonClassName}`,
59
+ "aria-label": "Close popup",
60
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-4 w-4" })
61
+ }
62
+ )
46
63
  ] });
47
64
  }
48
65
 
@@ -59,6 +76,7 @@ function PopupButtons({ children, alignment = "center", className = "" }) {
59
76
 
60
77
  // src/popup/BasePopup.tsx
61
78
  var import_react_dom = require("react-dom");
79
+ var import_react = require("react");
62
80
  var import_ui2 = require("@behindthemusictree/ui");
63
81
  var import_jsx_runtime3 = require("react/jsx-runtime");
64
82
  var typeClasses = {
@@ -83,7 +101,12 @@ function BasePopup(props) {
83
101
  icon,
84
102
  isDismissable = true,
85
103
  className,
104
+ overlayClassName = "",
105
+ titleClassName = "",
106
+ titleTextClassName = "",
107
+ closeButtonClassName = "",
86
108
  fitContent = false,
109
+ contentClassName = "",
87
110
  showOkButton = false,
88
111
  showCancelButton = false,
89
112
  okButtonText = "OK",
@@ -92,8 +115,49 @@ function BasePopup(props) {
92
115
  okButtonDisabled = false,
93
116
  onCancel,
94
117
  buttonAlignment = "center",
95
- topOffset = 0
118
+ topOffset = 0,
119
+ trapFocus = false,
120
+ closeOnEscape = false,
121
+ closeOnBackdrop = false
96
122
  } = props;
123
+ const dialogRef = (0, import_react.useRef)(null);
124
+ (0, import_react.useEffect)(() => {
125
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
126
+ const dialog = dialogRef.current;
127
+ const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
128
+ const getFocusable = () => Array.from(dialog?.querySelectorAll(focusableSelector) ?? []).filter(
129
+ (element) => !element.hasAttribute("hidden") && element.getAttribute("aria-hidden") !== "true"
130
+ );
131
+ if (trapFocus) (getFocusable()[0] ?? dialog)?.focus();
132
+ const handleKeyDown = (event) => {
133
+ if (event.key === "Escape" && closeOnEscape && isDismissable) {
134
+ event.preventDefault();
135
+ onClose?.();
136
+ return;
137
+ }
138
+ if (!trapFocus || event.key !== "Tab") return;
139
+ const focusable = getFocusable();
140
+ if (focusable.length === 0) {
141
+ event.preventDefault();
142
+ dialog?.focus();
143
+ return;
144
+ }
145
+ const first = focusable[0];
146
+ const last = focusable[focusable.length - 1];
147
+ if (event.shiftKey && (document.activeElement === first || !dialog?.contains(document.activeElement))) {
148
+ event.preventDefault();
149
+ last.focus();
150
+ } else if (!event.shiftKey && (document.activeElement === last || !dialog?.contains(document.activeElement))) {
151
+ event.preventDefault();
152
+ first.focus();
153
+ }
154
+ };
155
+ if (trapFocus || closeOnEscape) document.addEventListener("keydown", handleKeyDown);
156
+ return () => {
157
+ if (trapFocus || closeOnEscape) document.removeEventListener("keydown", handleKeyDown);
158
+ if (trapFocus && previousFocus?.isConnected) previousFocus.focus();
159
+ };
160
+ }, [closeOnEscape, isDismissable, onClose, trapFocus]);
97
161
  const baseClasses = "bg-white rounded-lg";
98
162
  const renderButtons = () => {
99
163
  if (!showOkButton && !showCancelButton) return null;
@@ -107,7 +171,7 @@ function BasePopup(props) {
107
171
  const popupComponent = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
108
172
  "div",
109
173
  {
110
- className: "fixed z-50 flex items-center justify-center bg-transparent",
174
+ className: `fixed z-50 flex items-center justify-center bg-transparent ${overlayClassName}`,
111
175
  style: {
112
176
  top: topOffset,
113
177
  left: 0,
@@ -117,15 +181,29 @@ function BasePopup(props) {
117
181
  role: "dialog",
118
182
  "aria-modal": "true",
119
183
  "aria-labelledby": "popup-title",
184
+ onClick: closeOnBackdrop && isDismissable ? onClose : void 0,
120
185
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
121
186
  "div",
122
187
  {
188
+ ref: dialogRef,
189
+ tabIndex: trapFocus ? -1 : void 0,
123
190
  className: `${baseClasses} ${fitContent ? typeClasses[type].replace("w-full", "w-fit") : typeClasses[type]} ${className || ""}`,
124
191
  onClick: (e) => e.stopPropagation(),
125
192
  children: [
126
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PopupTitle, { title, onClose: onClose ?? (() => {
127
- }), isDismissable, icon }),
128
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? ""}`, children: [
193
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
194
+ PopupTitle,
195
+ {
196
+ title,
197
+ onClose: onClose ?? (() => {
198
+ }),
199
+ isDismissable,
200
+ icon,
201
+ className: titleClassName,
202
+ titleClassName: titleTextClassName,
203
+ closeButtonClassName
204
+ }
205
+ ),
206
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? ""} ${contentClassName}`, children: [
129
207
  children,
130
208
  renderButtons()
131
209
  ] })
@@ -137,21 +215,48 @@ function BasePopup(props) {
137
215
  return (0, import_react_dom.createPortal)(popupComponent, document.body);
138
216
  }
139
217
 
218
+ // src/popup/Toast.tsx
219
+ var import_react2 = require("react");
220
+ var import_react_dom2 = require("react-dom");
221
+ var import_jsx_runtime4 = require("react/jsx-runtime");
222
+ function Toast({ message, onClose, durationMs = 2200 }) {
223
+ const [mounted, setMounted] = (0, import_react2.useState)(false);
224
+ (0, import_react2.useEffect)(() => {
225
+ setMounted(true);
226
+ const timeout = window.setTimeout(onClose, durationMs);
227
+ return () => window.clearTimeout(timeout);
228
+ }, [durationMs, onClose]);
229
+ if (!mounted) return null;
230
+ return (0, import_react_dom2.createPortal)(
231
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
232
+ "div",
233
+ {
234
+ role: "status",
235
+ "aria-live": "polite",
236
+ "aria-atomic": "true",
237
+ className: "pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-sm text-[var(--color-text)] shadow-lg ring-1 ring-black/10",
238
+ children: message
239
+ }
240
+ ) }),
241
+ document.body
242
+ );
243
+ }
244
+
140
245
  // src/popup/TrackUploadPopup.tsx
141
246
  var import_md = require("react-icons/md");
142
247
  var import_popup = require("@behindthemusictree/app-kit/popup");
143
248
  var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
144
- var import_jsx_runtime4 = require("react/jsx-runtime");
249
+ var import_jsx_runtime5 = require("react/jsx-runtime");
145
250
  function getStatusIcon(status) {
146
251
  switch (status) {
147
252
  case "success":
148
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_md.MdCheckCircle, { className: "text-[var(--color-green-500)]", size: 20 });
253
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_md.MdCheckCircle, { className: "text-[var(--color-green-500)]", size: 20 });
149
254
  case "error":
150
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_md.MdError, { className: "text-[var(--color-red-500)]", size: 20 });
255
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_md.MdError, { className: "text-[var(--color-red-500)]", size: 20 });
151
256
  case "uploading":
152
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_md.MdUpload, { className: "text-[var(--color-blue-500)] animate-pulse", size: 20 });
257
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_md.MdUpload, { className: "text-[var(--color-blue-500)] animate-pulse", size: 20 });
153
258
  default:
154
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-5 h-5 rounded-full border-2 border-[var(--color-neutral-300)]" });
259
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-5 h-5 rounded-full border-2 border-[var(--color-neutral-300)]" });
155
260
  }
156
261
  }
157
262
  function getStatusText(status) {
@@ -184,7 +289,7 @@ function TrackUploadPopup({
184
289
  });
185
290
  const displayTotal = items.length > 0 ? items.length : files.length;
186
291
  const trackNoun = (0, import_track_noun.useTrackNoun)();
187
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
292
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
188
293
  BasePopup,
189
294
  {
190
295
  ...rest,
@@ -195,31 +300,31 @@ function TrackUploadPopup({
195
300
  okButtonText: "OK",
196
301
  okButtonDisabled: isUploading || !allComplete,
197
302
  onOk: onClose,
198
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-4", children: [
199
- items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "border rounded-lg p-4", children: [
200
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
201
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center space-x-3", children: [
303
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "space-y-4", children: [
304
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "border rounded-lg p-4", children: [
305
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
306
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center space-x-3", children: [
202
307
  getStatusIcon(item.status),
203
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
204
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "font-medium text-sm truncate max-w-xs", title: item.file.name, children: item.file.name }),
205
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-xs text-[var(--color-neutral-500)]", children: [
308
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
309
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "font-medium text-sm truncate max-w-xs", title: item.file.name, children: item.file.name }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "text-xs text-[var(--color-neutral-500)]", children: [
206
311
  (item.file.size / 1024 / 1024).toFixed(1),
207
312
  " MB"
208
313
  ] })
209
314
  ] })
210
315
  ] }),
211
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-sm text-[var(--color-neutral-600)]", children: getStatusText(item.status) })
316
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-sm text-[var(--color-neutral-600)]", children: getStatusText(item.status) })
212
317
  ] }),
213
- item.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-full bg-[var(--color-neutral-200)] rounded-full h-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
318
+ item.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-full bg-[var(--color-neutral-200)] rounded-full h-2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
214
319
  "div",
215
320
  {
216
321
  className: "bg-[var(--color-blue-500)] h-2 rounded-full transition-all duration-300",
217
322
  style: { width: `${item.progress}%` }
218
323
  }
219
324
  ) }),
220
- item.status === "error" && item.error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-[var(--color-red-500)] text-sm mt-2", children: item.error.name === "InvalidInputError" ? "Upload failed due to invalid file data. Please check your file and try again." : item.error.name === "ZodError" ? "Upload failed due to a server error. Please try again later." : item.error.message })
325
+ item.status === "error" && item.error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "text-[var(--color-red-500)] text-sm mt-2", children: item.error.name === "InvalidInputError" ? "Upload failed due to invalid file data. Please check your file and try again." : item.error.name === "ZodError" ? "Upload failed due to a server error. Please try again later." : item.error.message })
221
326
  ] }, item.id)),
222
- allComplete && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-sm text-[var(--color-neutral-600)]", children: [
327
+ allComplete && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "text-sm text-[var(--color-neutral-600)]", children: [
223
328
  successfulCount,
224
329
  " successful, ",
225
330
  errorCount,
@@ -233,18 +338,18 @@ function TrackUploadPopup({
233
338
  // src/popup/AuthErrorPopup.tsx
234
339
  var import_lucide_react2 = require("lucide-react");
235
340
  var import_ui3 = require("@behindthemusictree/ui");
236
- var import_jsx_runtime5 = require("react/jsx-runtime");
341
+ var import_jsx_runtime6 = require("react/jsx-runtime");
237
342
  function AuthErrorPopup({ message, onClose, ...rest }) {
238
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
343
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
239
344
  BasePopup,
240
345
  {
241
346
  ...rest,
242
347
  title: "Sign-in error",
243
348
  isDismissable: true,
244
349
  icon: import_lucide_react2.AlertCircle,
245
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
246
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-center text-lg font-medium text-[var(--color-text)]", children: message }),
247
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ui3.Button, { onClick: onClose, variant: "secondary", className: "w-full max-w-xs", children: "Close" })
350
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
351
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-center text-lg font-medium text-[var(--color-text)]", children: message }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ui3.Button, { onClick: onClose, variant: "secondary", className: "w-full max-w-xs", children: "Close" })
248
353
  ] })
249
354
  }
250
355
  );
@@ -252,23 +357,23 @@ function AuthErrorPopup({ message, onClose, ...rest }) {
252
357
 
253
358
  // src/popup/InternalErrorPopup.tsx
254
359
  var import_lucide_react3 = require("lucide-react");
255
- var import_jsx_runtime6 = require("react/jsx-runtime");
360
+ var import_jsx_runtime7 = require("react/jsx-runtime");
256
361
  function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
257
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
362
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
258
363
  BasePopup,
259
364
  {
260
365
  ...rest,
261
366
  title: "Internal Error",
262
367
  isDismissable: false,
263
368
  icon: import_lucide_react3.AlertTriangle,
264
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
265
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.AlertCircle, { className: "h-16 w-16 text-[var(--color-red-500)]", strokeWidth: 1.5 }),
266
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "text-center text-[var(--color-neutral-600)]", children: [
369
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.AlertCircle, { className: "h-16 w-16 text-[var(--color-red-500)]", strokeWidth: 1.5 }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-center text-[var(--color-neutral-600)]", children: [
267
372
  "Please try again. If the problem persists, contact us at",
268
373
  " ",
269
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: `mailto:${contactEmail}`, className: "text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]", children: contactEmail })
374
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { href: `mailto:${contactEmail}`, className: "text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]", children: contactEmail })
270
375
  ] }) }),
271
- errorCode && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: [
376
+ errorCode && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "text-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: [
272
377
  "Error Code: ",
273
378
  errorCode
274
379
  ] })
@@ -279,18 +384,18 @@ function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
279
384
 
280
385
  // src/popup/NetworkErrorPopup.tsx
281
386
  var import_lucide_react4 = require("lucide-react");
282
- var import_jsx_runtime7 = require("react/jsx-runtime");
387
+ var import_jsx_runtime8 = require("react/jsx-runtime");
283
388
  function NetworkErrorPopup(props) {
284
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
389
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
285
390
  BasePopup,
286
391
  {
287
392
  ...props,
288
393
  title: "Network Error",
289
394
  isDismissable: false,
290
395
  icon: import_lucide_react4.AlertTriangle,
291
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
292
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.AlertTriangle, { className: "h-16 w-16 text-[var(--color-neutral-600)]", strokeWidth: 1.5 }),
293
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-center text-[var(--color-neutral-700)]", children: "It seems that you are not connected to the internet. Please check your connection and try again." })
396
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col items-center space-y-6 py-4", children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.AlertTriangle, { className: "h-16 w-16 text-[var(--color-neutral-600)]", strokeWidth: 1.5 }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-center text-[var(--color-neutral-700)]", children: "It seems that you are not connected to the internet. Please check your connection and try again." })
294
399
  ] })
295
400
  }
296
401
  );
@@ -301,7 +406,7 @@ var import_lucide_react5 = require("lucide-react");
301
406
  var import_ui4 = require("@behindthemusictree/ui");
302
407
  var import_fa = require("react-icons/fa");
303
408
  var import_fc = require("react-icons/fc");
304
- var import_jsx_runtime8 = require("react/jsx-runtime");
409
+ var import_jsx_runtime9 = require("react/jsx-runtime");
305
410
  function AuthPopup({
306
411
  handleSpotifyOAuth,
307
412
  handleGoogleOAuth,
@@ -313,7 +418,7 @@ function AuthPopup({
313
418
  ...rest
314
419
  }) {
315
420
  const showGoogle = !spotifyOnly && handleGoogleOAuth;
316
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
421
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
317
422
  BasePopup,
318
423
  {
319
424
  ...rest,
@@ -321,32 +426,32 @@ function AuthPopup({
321
426
  isDismissable: false,
322
427
  icon: import_lucide_react5.User,
323
428
  type: "auth",
324
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col items-center space-y-7", children: [
325
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "px-2 text-center", children: [
326
- message && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "mb-3 text-base font-medium leading-relaxed text-amber-200", children: message }),
327
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-lg font-medium leading-relaxed text-white", children: spotifyOnly ? spotifyOnlyDescription : defaultDescription })
429
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col items-center space-y-7", children: [
430
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "px-2 text-center", children: [
431
+ message && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "mb-3 text-base font-medium leading-relaxed text-amber-200", children: message }),
432
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-lg font-medium leading-relaxed text-white", children: spotifyOnly ? spotifyOnlyDescription : defaultDescription })
328
433
  ] }),
329
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex w-full flex-col items-center gap-3", children: [
330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
434
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex w-full flex-col items-center gap-3", children: [
435
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
331
436
  import_ui4.Button,
332
437
  {
333
438
  onClick: () => handleSpotifyOAuth(redirectAfterAuthPath),
334
439
  className: "relative mb-2 w-fit transform bg-green-600 px-8 py-3 text-white shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-green-700 hover:shadow-xl",
335
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center justify-center", children: [
336
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_fa.FaSpotify, { className: "absolute left-6 text-3xl" }),
337
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-full pl-14 pr-8 text-center text-lg font-medium", children: "Sign in with Spotify" })
440
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex items-center justify-center", children: [
441
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fa.FaSpotify, { className: "absolute left-6 text-3xl" }),
442
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-full pl-14 pr-8 text-center text-lg font-medium", children: "Sign in with Spotify" })
338
443
  ] })
339
444
  }
340
445
  ),
341
- showGoogle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
446
+ showGoogle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
342
447
  import_ui4.Button,
343
448
  {
344
449
  variant: "outline",
345
450
  onClick: () => handleGoogleOAuth(redirectAfterAuthPath),
346
451
  className: "relative w-fit transform border-white bg-white px-8 py-3 text-black shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-[var(--color-neutral-100)] hover:shadow-xl",
347
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "flex items-center justify-center", children: [
348
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_fc.FcGoogle, { className: "absolute left-6 text-2xl" }),
349
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "w-full pl-14 pr-8 text-center text-lg font-medium text-black", children: "Sign in with Google" })
452
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex items-center justify-center", children: [
453
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fc.FcGoogle, { className: "absolute left-6 text-2xl" }),
454
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-full pl-14 pr-8 text-center text-lg font-medium text-black", children: "Sign in with Google" })
350
455
  ] })
351
456
  }
352
457
  )
@@ -361,7 +466,7 @@ var import_fa2 = require("react-icons/fa");
361
466
  var import_ui5 = require("@behindthemusictree/ui");
362
467
  var import_lucide_react6 = require("lucide-react");
363
468
  var import_transport = require("@behindthemusictree/app-kit/transport");
364
- var import_jsx_runtime9 = require("react/jsx-runtime");
469
+ var import_jsx_runtime10 = require("react/jsx-runtime");
365
470
  function SpotifyAuthErrorPopup({
366
471
  message,
367
472
  details,
@@ -370,24 +475,24 @@ function SpotifyAuthErrorPopup({
370
475
  ...rest
371
476
  }) {
372
477
  const requestAccessHref = (0, import_transport.getSpotifyAllowlistMailtoHref)(contactEmail);
373
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
478
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
374
479
  BasePopup,
375
480
  {
376
481
  ...rest,
377
482
  title: "Authentication Failed",
378
483
  isDismissable: true,
379
484
  icon: import_lucide_react6.User,
380
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col items-center space-y-8 py-4", children: [
381
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fa2.FaSpotify, { className: "text-[#1DB954] text-7xl" }),
382
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-3 text-center", children: [
383
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xl font-medium text-[var(--color-text)]", children: message }),
384
- details && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: details }),
385
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2 text-center", children: [
386
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-base text-[var(--color-neutral-700)]", children: "The Spotify app is in development mode, so only allowlisted accounts can connect." }),
387
- requestAccessHref && contactEmail ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "text-base text-[var(--color-neutral-700)]", children: [
485
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center space-y-8 py-4", children: [
486
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_fa2.FaSpotify, { className: "text-[#1DB954] text-7xl" }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-3 text-center", children: [
488
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-xl font-medium text-[var(--color-text)]", children: message }),
489
+ details && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: details }),
490
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "space-y-2 text-center", children: [
491
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-base text-[var(--color-neutral-700)]", children: "The Spotify app is in development mode, so only allowlisted accounts can connect." }),
492
+ requestAccessHref && contactEmail ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "text-base text-[var(--color-neutral-700)]", children: [
388
493
  "Request access by emailing your",
389
494
  " ",
390
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
495
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
391
496
  "a",
392
497
  {
393
498
  href: requestAccessHref,
@@ -398,7 +503,7 @@ function SpotifyAuthErrorPopup({
398
503
  " ",
399
504
  "to",
400
505
  " ",
401
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
506
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
402
507
  "a",
403
508
  {
404
509
  href: requestAccessHref,
@@ -407,16 +512,16 @@ function SpotifyAuthErrorPopup({
407
512
  }
408
513
  ),
409
514
  "."
410
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-base text-[var(--color-neutral-700)]", children: "To request access, contact the app owner." })
515
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-base text-[var(--color-neutral-700)]", children: "To request access, contact the app owner." })
411
516
  ] })
412
517
  ] }),
413
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
518
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
414
519
  import_ui5.Button,
415
520
  {
416
521
  onClick: onClose,
417
522
  className: "bg-[#1DB954] hover:bg-[#1DB954]/90 text-white w-full max-w-xs transform transition-all duration-200 hover:scale-[1.02] shadow-lg hover:shadow-xl",
418
523
  children: [
419
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_fa2.FaSpotify, { className: "mr-2 text-lg" }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_fa2.FaSpotify, { className: "mr-2 text-lg" }),
420
525
  "Try Again"
421
526
  ]
422
527
  }
@@ -435,6 +540,7 @@ function SpotifyAuthErrorPopup({
435
540
  PopupButtons,
436
541
  PopupTitle,
437
542
  SpotifyAuthErrorPopup,
543
+ Toast,
438
544
  TrackUploadPopup
439
545
  });
440
546
  //# sourceMappingURL=index.cjs.map