saltfish 0.3.18 → 0.3.19
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/core/services/PlaylistOrchestrator.d.ts.map +1 -1
- package/dist/core/services/StateMachineActionHandler.d.ts.map +1 -1
- package/dist/managers/UIManager.d.ts +9 -0
- package/dist/managers/UIManager.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +76 -1
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/styles/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2843,6 +2843,9 @@ class PlaylistOrchestrator {
|
|
|
2843
2843
|
if (updatedStore.manifest.compactFirstStep && isFirstStep && isTriggeredAutomatically) {
|
|
2844
2844
|
const playerElement = this.managers.uiManager.getPlayerElement();
|
|
2845
2845
|
playerElement == null ? void 0 : playerElement.classList.add("sf-player--compact");
|
|
2846
|
+
if (updatedStore.manifest.compactLabel) {
|
|
2847
|
+
this.managers.uiManager.showCompactLabel(updatedStore.manifest.compactLabel);
|
|
2848
|
+
}
|
|
2846
2849
|
}
|
|
2847
2850
|
if (updatedStore.manifest.idleMode && isTriggeredAutomatically) {
|
|
2848
2851
|
store.setIdleMode();
|
|
@@ -3105,6 +3108,7 @@ class StateMachineActionHandler {
|
|
|
3105
3108
|
this.managers.uiManager.updatePosition();
|
|
3106
3109
|
const playerElement = this.managers.uiManager.getPlayerElement();
|
|
3107
3110
|
playerElement == null ? void 0 : playerElement.classList.remove("sf-player--compact");
|
|
3111
|
+
this.managers.uiManager.hideCompactLabel();
|
|
3108
3112
|
this.managers.uiManager.showPlayer();
|
|
3109
3113
|
const videoUrl = this.getVideoUrl(currentStep);
|
|
3110
3114
|
const isAudioFallback = this.isUsingAudioFallback(currentStep);
|
|
@@ -3905,6 +3909,7 @@ const componentsTranscriptCss = "/* \n * Transcript component styles for the Sal
|
|
|
3905
3909
|
const componentsErrorCss = "/* \n * Error Display component styles for the Saltfish playlist Player\n * Clean and subtle full-widget error overlay\n */\n\n/* Error display overlay - covers full widget */\n.sf-error-display {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: calc(var(--sf-z-index-controls) + 30);\n border-radius: var(--sf-border-radius-lg);\n opacity: 0;\n transition: opacity var(--sf-transition-slow);\n pointer-events: auto;\n}\n\n/* Error display visible state */\n.sf-error-display--visible {\n opacity: 1;\n}\n\n/* Error content container */\n.sf-error-display__content {\n background-color: rgba(20, 20, 20, 0.9);\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-lg) var(--sf-spacing-xl);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n transform: translateY(8px);\n transition: transform var(--sf-transition-slow);\n max-width: 85%;\n text-align: center;\n}\n\n/* Error content visible animation */\n.sf-error-display--visible .sf-error-display__content {\n transform: translateY(0);\n}\n\n/* Error message */\n.sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--sf-font-size-md);\n line-height: 1.5;\n margin: 0;\n text-align: center;\n font-weight: 500;\n}\n\n/* Mobile responsive adjustments */\n@media (max-width: 768px) {\n .sf-error-display__content {\n padding: var(--sf-spacing-md) var(--sf-spacing-lg);\n max-width: 90%;\n }\n\n .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n }\n}\n\n/* Minimized player state adjustments */\n.sf-player--minimized .sf-error-display__content {\n padding: var(--sf-spacing-sm) var(--sf-spacing-md);\n max-width: 80%;\n}\n\n.sf-player--minimized .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n font-weight: 400;\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .sf-error-display__content {\n background-color: rgba(0, 0, 0, 0.95);\n border: 2px solid rgba(255, 255, 255, 0.3);\n }\n\n .sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .sf-error-display,\n .sf-error-display__content {\n transition: none;\n }\n}";
|
|
3906
3910
|
const componentsLoadingCss = "/**\n * Loading spinner styles\n */\n\n.sf-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n z-index: 100;\n border-radius: 12px;\n opacity: 1 !important; /* Always visible when shown, overrides parent opacity */\n}\n\n.sf-loading-spinner__content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n}\n\n.sf-loading-spinner__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: #000000;\n opacity: 0.9;\n}\n\n.sf-loading-spinner__icon svg {\n width: 60px;\n height: 60px;\n /* Remove the rotation animation since we now have internal SVG animation */\n}\n\n.sf-loading-spinner__text {\n color: #333333;\n font-size: 14px;\n font-weight: 500;\n text-align: center;\n opacity: 0.8;\n letter-spacing: 0.5px;\n}\n\n/* CSS keyframe animation removed - using SVG animateTransform instead */\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .sf-loading-spinner__content {\n padding: 20px;\n gap: 10px;\n }\n \n .sf-loading-spinner__icon svg {\n width: 50px;\n height: 50px;\n }\n \n .sf-loading-spinner__text {\n font-size: 13px;\n }\n}";
|
|
3907
3911
|
const componentsCursorCss = "/*\n * Cursor animation component styles for the Saltfish playlist Player\n * CSP-compliant: All styles use CSS classes and CSS custom properties instead of inline styles\n */\n\n/* Base cursor element */\n.sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 36px;\n height: 36px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n}\n\n.sf-cursor--visible {\n display: block;\n}\n\n/* Selection element */\n.sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n border: 2px solid var(--sf-selection-color, #ff7614);\n background: var(--sf-selection-bg-color, rgba(255, 118, 20, 0.1));\n border-radius: 4px;\n left: var(--sf-selection-left, 0);\n top: var(--sf-selection-top, 0);\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n}\n\n.sf-selection--visible {\n display: block;\n}\n\n/* Flashlight overlay */\n.sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n}\n\n.sf-flashlight-overlay--visible {\n display: block;\n}\n";
|
|
3912
|
+
const componentsCompactLabelCss = "/**\n * Compact Label Styles\n * Label that appears next to the player when in compact first step mode\n * Position adapts based on player placement (left/right)\n */\n\n.sf-compact-label {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n\n /* Typography */\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n color: #ffffff;\n\n /* Visual styling */\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(10px);\n padding: 10px 16px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3),\n 0 0 0 1px rgba(255, 255, 255, 0.1);\n\n /* Ensure it doesn't wrap */\n white-space: nowrap;\n\n /* Layering */\n z-index: 10;\n\n /* Pointer events - will be enabled via JS when clickable */\n pointer-events: none;\n user-select: none;\n\n /* Smooth transitions for hover effects */\n transition: transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n box-shadow 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n background 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Position to the LEFT of player (when player is on the right side) */\n.sf-compact-label--left {\n right: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-left 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Position to the RIGHT of player (when player is on the left side) */\n.sf-compact-label--right {\n left: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-right 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Entrance animation from LEFT - slide in from left with fade */\n@keyframes sf-compact-label-enter-from-left {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(-20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Entrance animation from RIGHT - slide in from right with fade */\n@keyframes sf-compact-label-enter-from-right {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Hover effect - only applies when label is clickable (pointer-events: auto) */\n.sf-compact-label--left:hover,\n.sf-compact-label--right:hover {\n background: rgba(0, 0, 0, 0.95);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4),\n 0 0 0 1px rgba(255, 255, 255, 0.2),\n 0 0 25px rgba(255, 255, 255, 0.08);\n}\n\n.sf-compact-label--left:hover {\n transform: translateY(-50%) translateX(-2px);\n}\n\n.sf-compact-label--right:hover {\n transform: translateY(-50%) translateX(2px);\n}\n\n/* Active/click state */\n.sf-compact-label--left:active,\n.sf-compact-label--right:active {\n transform: translateY(-50%) scale(0.98);\n}\n\n/* Mobile adjustments */\n@media (max-width: 768px) {\n .sf-compact-label {\n font-size: 12px;\n padding: 8px 12px;\n }\n\n .sf-compact-label--left {\n right: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n\n .sf-compact-label--right {\n left: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n}\n\n/* Very small screens - position below instead of to the side */\n@media (max-width: 480px) {\n .sf-compact-label--left,\n .sf-compact-label--right {\n left: 50%;\n right: auto;\n top: calc(100% + 12px);\n transform: translateX(-50%);\n animation: sf-compact-label-enter-below 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n }\n\n @keyframes sf-compact-label-enter-below {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n 100% {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n}\n";
|
|
3908
3913
|
const animationsTransitionsCss = "/* \n * Transitions and animations for Saltfish playlist Player\n */\n\n/* Fade in animation */\n@keyframes sf-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sf-fade-in {\n animation: sf-fade-in 0.3s ease-in-out forwards;\n}\n\n/* Slide in from bottom animation */\n@keyframes sf-slide-in-bottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n\n.sf-slide-in-bottom {\n animation: sf-slide-in-bottom 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Slide in from right animation */\n@keyframes sf-slide-in-right {\n from { transform: translateX(100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n}\n\n.sf-slide-in-right {\n animation: sf-slide-in-right 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale in animation */\n@keyframes sf-scale-in {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.sf-scale-in {\n animation: sf-scale-in 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale out animation */\n@keyframes sf-scale-out {\n from { transform: scale(1); opacity: 1; }\n to { transform: scale(0.8); opacity: 0; }\n}\n\n.sf-scale-out {\n animation: sf-scale-out 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n} ";
|
|
3909
3914
|
const getPlayerStyles = () => `
|
|
3910
3915
|
${baseResetCss}
|
|
@@ -3917,6 +3922,7 @@ const getPlayerStyles = () => `
|
|
|
3917
3922
|
${componentsErrorCss}
|
|
3918
3923
|
${componentsLoadingCss}
|
|
3919
3924
|
${componentsCursorCss}
|
|
3925
|
+
${componentsCompactLabelCss}
|
|
3920
3926
|
|
|
3921
3927
|
${animationsTransitionsCss}
|
|
3922
3928
|
`;
|
|
@@ -10565,6 +10571,7 @@ class UIManager {
|
|
|
10565
10571
|
__publicField(this, "playPauseButton", null);
|
|
10566
10572
|
__publicField(this, "errorDisplay", null);
|
|
10567
10573
|
__publicField(this, "loadingSpinner", null);
|
|
10574
|
+
__publicField(this, "compactLabel", null);
|
|
10568
10575
|
// Button management properties (from ButtonManager)
|
|
10569
10576
|
__publicField(this, "playbackButtonsVisible", false);
|
|
10570
10577
|
__publicField(this, "playButton", null);
|
|
@@ -10952,6 +10959,73 @@ class UIManager {
|
|
|
10952
10959
|
}
|
|
10953
10960
|
});
|
|
10954
10961
|
}
|
|
10962
|
+
/**
|
|
10963
|
+
* Shows the compact label next to the player with the provided text
|
|
10964
|
+
*/
|
|
10965
|
+
showCompactLabel(labelText) {
|
|
10966
|
+
var _a;
|
|
10967
|
+
if (!this.playerRoot || !labelText) {
|
|
10968
|
+
return;
|
|
10969
|
+
}
|
|
10970
|
+
this.hideCompactLabel();
|
|
10971
|
+
const store = useSaltfishStore.getState();
|
|
10972
|
+
let positionToUse = ((_a = store.playlistOptions) == null ? void 0 : _a.position) || "bottom-right";
|
|
10973
|
+
if (store.currentStepId && store.manifest) {
|
|
10974
|
+
const currentStep = store.manifest.steps.find((step) => step.id === store.currentStepId);
|
|
10975
|
+
if (currentStep == null ? void 0 : currentStep.position) {
|
|
10976
|
+
positionToUse = currentStep.position;
|
|
10977
|
+
}
|
|
10978
|
+
}
|
|
10979
|
+
const isPlayerOnRight = positionToUse === "bottom-right";
|
|
10980
|
+
const labelPositionClass = isPlayerOnRight ? "sf-compact-label--left" : "sf-compact-label--right";
|
|
10981
|
+
this.compactLabel = document.createElement("div");
|
|
10982
|
+
this.compactLabel.className = `sf-compact-label ${labelPositionClass}`;
|
|
10983
|
+
this.compactLabel.textContent = labelText;
|
|
10984
|
+
this.compactLabel.style.cursor = "pointer";
|
|
10985
|
+
this.compactLabel.style.pointerEvents = "auto";
|
|
10986
|
+
this.compactLabel.addEventListener("click", (e) => {
|
|
10987
|
+
var _a2;
|
|
10988
|
+
e.stopPropagation();
|
|
10989
|
+
e.preventDefault();
|
|
10990
|
+
const currentStore = useSaltfishStore.getState();
|
|
10991
|
+
if (currentStore.currentState === "autoplayBlocked" || currentStore.currentState === "idleMode") {
|
|
10992
|
+
currentStore.currentState === "autoplayBlocked" ? "autoplay fallback" : "idle";
|
|
10993
|
+
if (this.videoManager) {
|
|
10994
|
+
this.videoManager.markUserInteraction();
|
|
10995
|
+
this.videoManager.setMuted(false);
|
|
10996
|
+
const videoElement = this.videoManager.getVideoElement();
|
|
10997
|
+
if (videoElement) {
|
|
10998
|
+
videoElement.loop = false;
|
|
10999
|
+
videoElement.currentTime = 0;
|
|
11000
|
+
}
|
|
11001
|
+
} else {
|
|
11002
|
+
const videoElement = (_a2 = this.playerElement) == null ? void 0 : _a2.querySelector(".sf-video-container__video");
|
|
11003
|
+
if (videoElement) {
|
|
11004
|
+
videoElement.muted = false;
|
|
11005
|
+
videoElement.loop = false;
|
|
11006
|
+
videoElement.currentTime = 0;
|
|
11007
|
+
}
|
|
11008
|
+
}
|
|
11009
|
+
} else {
|
|
11010
|
+
if (this.videoManager) {
|
|
11011
|
+
this.videoManager.markUserInteraction();
|
|
11012
|
+
}
|
|
11013
|
+
}
|
|
11014
|
+
if (currentStore.currentState === "paused" || currentStore.currentState === "waitingForInteraction" || currentStore.currentState === "completedWaitingForInteraction" || currentStore.currentState === "autoplayBlocked" || currentStore.currentState === "idleMode" || currentStore.currentState === "error") {
|
|
11015
|
+
currentStore.play();
|
|
11016
|
+
}
|
|
11017
|
+
});
|
|
11018
|
+
this.playerRoot.appendChild(this.compactLabel);
|
|
11019
|
+
}
|
|
11020
|
+
/**
|
|
11021
|
+
* Hides and removes the compact label
|
|
11022
|
+
*/
|
|
11023
|
+
hideCompactLabel() {
|
|
11024
|
+
if (this.compactLabel && this.compactLabel.parentNode) {
|
|
11025
|
+
this.compactLabel.parentNode.removeChild(this.compactLabel);
|
|
11026
|
+
this.compactLabel = null;
|
|
11027
|
+
}
|
|
11028
|
+
}
|
|
10955
11029
|
/**
|
|
10956
11030
|
* Resets the UI manager to initial state for reuse
|
|
10957
11031
|
*/
|
|
@@ -10976,6 +11050,7 @@ class UIManager {
|
|
|
10976
11050
|
this.loadingSpinner.destroy();
|
|
10977
11051
|
this.loadingSpinner = null;
|
|
10978
11052
|
}
|
|
11053
|
+
this.hideCompactLabel();
|
|
10979
11054
|
if (this.playerElement && this.playerElement.parentNode) {
|
|
10980
11055
|
this.playerElement.parentNode.removeChild(this.playerElement);
|
|
10981
11056
|
}
|
|
@@ -11378,7 +11453,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
11378
11453
|
__proto__: null,
|
|
11379
11454
|
SaltfishPlayer
|
|
11380
11455
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
11381
|
-
const version = "0.3.
|
|
11456
|
+
const version = "0.3.19";
|
|
11382
11457
|
const packageJson = {
|
|
11383
11458
|
version
|
|
11384
11459
|
};
|