saltfish 0.3.38 → 0.3.41
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/managers/CursorManager.d.ts +21 -1
- package/dist/managers/CursorManager.d.ts.map +1 -1
- package/dist/managers/TriggerManager.d.ts +18 -0
- package/dist/managers/TriggerManager.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 +206 -2
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2845,6 +2845,9 @@ class PlaylistOrchestrator {
|
|
|
2845
2845
|
if (updatedStore.manifest.cursorColor) {
|
|
2846
2846
|
this.managers.cursorManager.setColor(updatedStore.manifest.cursorColor);
|
|
2847
2847
|
}
|
|
2848
|
+
if (updatedStore.manifest.cursorLabel) {
|
|
2849
|
+
this.managers.cursorManager.setLabel(updatedStore.manifest.cursorLabel);
|
|
2850
|
+
}
|
|
2848
2851
|
const isTriggeredAutomatically = finalOptions._triggeredByTriggerManager === true;
|
|
2849
2852
|
const isFirstStep = updatedStore.currentStepId === ((_e = updatedStore.manifest.steps[0]) == null ? void 0 : _e.id);
|
|
2850
2853
|
if (updatedStore.manifest.idleMode && isFirstStep) {
|
|
@@ -6713,6 +6716,9 @@ class CursorManager {
|
|
|
6713
6716
|
__publicField(this, "isSelectionMode", false);
|
|
6714
6717
|
__publicField(this, "selectionPadding", 4);
|
|
6715
6718
|
// Default padding in pixels
|
|
6719
|
+
// Label element for cursor name/text
|
|
6720
|
+
__publicField(this, "labelElement", null);
|
|
6721
|
+
__publicField(this, "labelText", null);
|
|
6716
6722
|
// Selection drag properties
|
|
6717
6723
|
__publicField(this, "dragStartX", null);
|
|
6718
6724
|
__publicField(this, "dragStartY", null);
|
|
@@ -7107,9 +7113,12 @@ class CursorManager {
|
|
|
7107
7113
|
<path d="M3.5 3.5L10.5 20.5L13.3 13.3L20.5 10.5L3.5 3.5Z" fill="#ff7614" stroke="white" stroke-width="0.7" stroke-linejoin="round" stroke-linecap="round" filter="url(#cursor-shadow)" />
|
|
7108
7114
|
</svg>
|
|
7109
7115
|
`;
|
|
7116
|
+
this.labelElement = document.createElement("div");
|
|
7117
|
+
this.labelElement.className = "sf-cursor-label";
|
|
7110
7118
|
this.selectionElement = document.createElement("div");
|
|
7111
7119
|
this.selectionElement.className = "sf-selection";
|
|
7112
7120
|
document.body.appendChild(this.cursor);
|
|
7121
|
+
document.body.appendChild(this.labelElement);
|
|
7113
7122
|
document.body.appendChild(this.selectionElement);
|
|
7114
7123
|
this.flashlightOverlay = document.createElement("div");
|
|
7115
7124
|
this.flashlightOverlay.className = "sf-flashlight-overlay";
|
|
@@ -7196,6 +7205,35 @@ class CursorManager {
|
|
|
7196
7205
|
.sf-flashlight-overlay--visible {
|
|
7197
7206
|
display: block;
|
|
7198
7207
|
}
|
|
7208
|
+
|
|
7209
|
+
.sf-cursor-label {
|
|
7210
|
+
position: fixed;
|
|
7211
|
+
top: 0;
|
|
7212
|
+
left: 0;
|
|
7213
|
+
z-index: 9999999;
|
|
7214
|
+
pointer-events: none;
|
|
7215
|
+
display: none;
|
|
7216
|
+
will-change: transform;
|
|
7217
|
+
transform: var(--sf-cursor-label-transform, translate(0, 0));
|
|
7218
|
+
opacity: var(--sf-cursor-opacity, 1);
|
|
7219
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
7220
|
+
font-size: 13px;
|
|
7221
|
+
font-weight: 500;
|
|
7222
|
+
color: var(--sf-cursor-label-text, #fff);
|
|
7223
|
+
background: var(--sf-cursor-label-bg, #ff7614);
|
|
7224
|
+
padding: 4px 10px;
|
|
7225
|
+
border-radius: 12px;
|
|
7226
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
7227
|
+
white-space: nowrap;
|
|
7228
|
+
margin: 0;
|
|
7229
|
+
border: 0;
|
|
7230
|
+
box-sizing: border-box;
|
|
7231
|
+
line-height: 1.4;
|
|
7232
|
+
}
|
|
7233
|
+
|
|
7234
|
+
.sf-cursor-label--visible {
|
|
7235
|
+
display: block;
|
|
7236
|
+
}
|
|
7199
7237
|
`;
|
|
7200
7238
|
try {
|
|
7201
7239
|
const sheet = new CSSStyleSheet();
|
|
@@ -7305,6 +7343,10 @@ class CursorManager {
|
|
|
7305
7343
|
this.cursor.classList.add("sf-cursor--visible");
|
|
7306
7344
|
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%)`);
|
|
7307
7345
|
}
|
|
7346
|
+
if (this.labelElement && this.labelText) {
|
|
7347
|
+
this.labelElement.classList.add("sf-cursor-label--visible");
|
|
7348
|
+
this.labelElement.style.setProperty("--sf-cursor-label-transform", `translate(${x + 24}px, ${y + 8}px)`);
|
|
7349
|
+
}
|
|
7308
7350
|
if (this.flashlightOverlay) {
|
|
7309
7351
|
this.flashlightOverlay.classList.add("sf-flashlight-overlay--visible");
|
|
7310
7352
|
this.flashlightOverlay.style.setProperty("--sf-flashlight-bg", `radial-gradient(circle 150px at ${x}px ${y}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`);
|
|
@@ -7317,6 +7359,9 @@ class CursorManager {
|
|
|
7317
7359
|
if (this.cursor) {
|
|
7318
7360
|
this.cursor.classList.remove("sf-cursor--visible");
|
|
7319
7361
|
}
|
|
7362
|
+
if (this.labelElement) {
|
|
7363
|
+
this.labelElement.classList.remove("sf-cursor-label--visible");
|
|
7364
|
+
}
|
|
7320
7365
|
if (this.selectionElement) {
|
|
7321
7366
|
this.selectionElement.classList.remove("sf-selection--visible");
|
|
7322
7367
|
}
|
|
@@ -7902,6 +7947,11 @@ class CursorManager {
|
|
|
7902
7947
|
this.cursor.remove();
|
|
7903
7948
|
this.cursor = null;
|
|
7904
7949
|
}
|
|
7950
|
+
if (this.labelElement && this.labelElement.parentNode) {
|
|
7951
|
+
this.labelElement.remove();
|
|
7952
|
+
this.labelElement = null;
|
|
7953
|
+
}
|
|
7954
|
+
this.labelText = null;
|
|
7905
7955
|
if (this.selectionElement && this.selectionElement.parentNode) {
|
|
7906
7956
|
this.selectionElement.remove();
|
|
7907
7957
|
this.selectionElement = null;
|
|
@@ -7922,7 +7972,7 @@ class CursorManager {
|
|
|
7922
7972
|
document.documentElement.style.removeProperty("--sf-cursor-y");
|
|
7923
7973
|
}
|
|
7924
7974
|
/**
|
|
7925
|
-
* Sets the color of the cursor SVG
|
|
7975
|
+
* Sets the color of the cursor SVG, selection highlight, and label
|
|
7926
7976
|
* @param color - The color to set (hex, rgb, etc)
|
|
7927
7977
|
*/
|
|
7928
7978
|
setColor(color) {
|
|
@@ -7946,6 +7996,46 @@ class CursorManager {
|
|
|
7946
7996
|
const rgbaBackground = this.colorToRgba(color, 0);
|
|
7947
7997
|
this.selectionElement.style.setProperty("--sf-selection-bg-color", rgbaBackground);
|
|
7948
7998
|
}
|
|
7999
|
+
if (this.labelElement) {
|
|
8000
|
+
this.labelElement.style.setProperty("--sf-cursor-label-bg", color);
|
|
8001
|
+
const textColor = this.getContrastingTextColor(color);
|
|
8002
|
+
this.labelElement.style.setProperty("--sf-cursor-label-text", textColor);
|
|
8003
|
+
}
|
|
8004
|
+
}
|
|
8005
|
+
/**
|
|
8006
|
+
* Calculates whether white or black text provides better contrast against a background color
|
|
8007
|
+
* Uses relative luminance calculation for accessibility
|
|
8008
|
+
* @param bgColor - The background color (hex, rgb, etc)
|
|
8009
|
+
* @returns '#fff' for dark backgrounds, '#333' for light backgrounds
|
|
8010
|
+
*/
|
|
8011
|
+
getContrastingTextColor(bgColor) {
|
|
8012
|
+
const rgb = this.parseColorToRgb(bgColor);
|
|
8013
|
+
if (!rgb) {
|
|
8014
|
+
return "#fff";
|
|
8015
|
+
}
|
|
8016
|
+
const luminance = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1e3;
|
|
8017
|
+
return luminance > 150 ? "#333" : "#fff";
|
|
8018
|
+
}
|
|
8019
|
+
/**
|
|
8020
|
+
* Parses a color string to RGB values
|
|
8021
|
+
* @param color - The color to parse (hex, rgb, rgba)
|
|
8022
|
+
* @returns RGB object or null if parsing fails
|
|
8023
|
+
*/
|
|
8024
|
+
parseColorToRgb(color) {
|
|
8025
|
+
const tempElement = document.createElement("div");
|
|
8026
|
+
tempElement.style.color = color;
|
|
8027
|
+
document.body.appendChild(tempElement);
|
|
8028
|
+
const computedColor = window.getComputedStyle(tempElement).color;
|
|
8029
|
+
document.body.removeChild(tempElement);
|
|
8030
|
+
const rgbMatch = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
8031
|
+
if (rgbMatch) {
|
|
8032
|
+
return {
|
|
8033
|
+
r: parseInt(rgbMatch[1], 10),
|
|
8034
|
+
g: parseInt(rgbMatch[2], 10),
|
|
8035
|
+
b: parseInt(rgbMatch[3], 10)
|
|
8036
|
+
};
|
|
8037
|
+
}
|
|
8038
|
+
return null;
|
|
7949
8039
|
}
|
|
7950
8040
|
/**
|
|
7951
8041
|
* Converts a color string (hex, rgb, rgba) to rgba format with specified opacity
|
|
@@ -7968,6 +8058,25 @@ class CursorManager {
|
|
|
7968
8058
|
}
|
|
7969
8059
|
return color;
|
|
7970
8060
|
}
|
|
8061
|
+
/**
|
|
8062
|
+
* Sets the label text to display beside the cursor
|
|
8063
|
+
* @param label - The label text to display (e.g., avatar name), or null to hide
|
|
8064
|
+
*/
|
|
8065
|
+
setLabel(label) {
|
|
8066
|
+
var _a;
|
|
8067
|
+
this.labelText = label;
|
|
8068
|
+
if (this.labelElement) {
|
|
8069
|
+
if (label) {
|
|
8070
|
+
this.labelElement.textContent = label;
|
|
8071
|
+
if ((_a = this.cursor) == null ? void 0 : _a.classList.contains("sf-cursor--visible")) {
|
|
8072
|
+
this.labelElement.classList.add("sf-cursor-label--visible");
|
|
8073
|
+
}
|
|
8074
|
+
} else {
|
|
8075
|
+
this.labelElement.textContent = "";
|
|
8076
|
+
this.labelElement.classList.remove("sf-cursor-label--visible");
|
|
8077
|
+
}
|
|
8078
|
+
}
|
|
8079
|
+
}
|
|
7971
8080
|
}
|
|
7972
8081
|
class InteractionManager {
|
|
7973
8082
|
constructor() {
|
|
@@ -9614,6 +9723,9 @@ class TriggerManager {
|
|
|
9614
9723
|
const elementVisibleCondition = this.evaluateElementVisibleCondition(triggers.elementVisible);
|
|
9615
9724
|
conditions.push(elementVisibleCondition);
|
|
9616
9725
|
log(`TriggerManager: ElementVisible condition for playlist ${playlistId}: ${elementVisibleCondition} (selector: ${triggers.elementVisible})`);
|
|
9726
|
+
const userAttributesCondition = this.evaluateUserAttributesCondition(triggers.userAttributes);
|
|
9727
|
+
conditions.push(userAttributesCondition);
|
|
9728
|
+
log(`TriggerManager: UserAttributes condition for playlist ${playlistId}: ${userAttributesCondition} (conditions: ${JSON.stringify(triggers.userAttributes)})`);
|
|
9617
9729
|
const shouldTrigger = this.applyOperators(conditions, triggers.operators);
|
|
9618
9730
|
log(`TriggerManager: Final evaluation for playlist ${playlistId}: ${shouldTrigger} (operator: ${triggers.operators.join(", ")})`);
|
|
9619
9731
|
if (shouldTrigger) {
|
|
@@ -9747,6 +9859,98 @@ class TriggerManager {
|
|
|
9747
9859
|
const isVisible = this.visibleElements.has(selector);
|
|
9748
9860
|
return isVisible;
|
|
9749
9861
|
}
|
|
9862
|
+
/**
|
|
9863
|
+
* Evaluates user attribute conditions for a playlist
|
|
9864
|
+
* All conditions must be met (AND logic)
|
|
9865
|
+
* @param conditions - Array of user attribute conditions to evaluate
|
|
9866
|
+
*/
|
|
9867
|
+
evaluateUserAttributesCondition(conditions) {
|
|
9868
|
+
if (!conditions || conditions.length === 0) {
|
|
9869
|
+
return true;
|
|
9870
|
+
}
|
|
9871
|
+
const store = getSaltfishStore();
|
|
9872
|
+
const user = store.user;
|
|
9873
|
+
if (!user) {
|
|
9874
|
+
return false;
|
|
9875
|
+
}
|
|
9876
|
+
for (const condition of conditions) {
|
|
9877
|
+
const { attributeKey, attributeType, operator, value: expectedValue } = condition;
|
|
9878
|
+
const userValue = user[attributeKey];
|
|
9879
|
+
if (userValue === void 0 || userValue === null) {
|
|
9880
|
+
return false;
|
|
9881
|
+
}
|
|
9882
|
+
const result = this.compareValues(userValue, expectedValue, attributeType, operator);
|
|
9883
|
+
if (!result) {
|
|
9884
|
+
return false;
|
|
9885
|
+
}
|
|
9886
|
+
}
|
|
9887
|
+
return true;
|
|
9888
|
+
}
|
|
9889
|
+
/**
|
|
9890
|
+
* Compares two values based on attribute type and operator
|
|
9891
|
+
* @param userValue - The user's actual value
|
|
9892
|
+
* @param expectedValue - The expected value from trigger condition (always a string)
|
|
9893
|
+
* @param attributeType - The data type for comparison
|
|
9894
|
+
* @param operator - The comparison operator
|
|
9895
|
+
*/
|
|
9896
|
+
compareValues(userValue, expectedValue, attributeType, operator) {
|
|
9897
|
+
try {
|
|
9898
|
+
switch (attributeType) {
|
|
9899
|
+
case "string": {
|
|
9900
|
+
const userStr = String(userValue);
|
|
9901
|
+
const expectedStr = expectedValue;
|
|
9902
|
+
return this.applyOperator(userStr, expectedStr, operator);
|
|
9903
|
+
}
|
|
9904
|
+
case "boolean": {
|
|
9905
|
+
const userBool = typeof userValue === "boolean" ? userValue : String(userValue).toLowerCase() === "true";
|
|
9906
|
+
const expectedBool = expectedValue.toLowerCase() === "true";
|
|
9907
|
+
if (operator === "equals") return userBool === expectedBool;
|
|
9908
|
+
if (operator === "notEquals") return userBool !== expectedBool;
|
|
9909
|
+
return false;
|
|
9910
|
+
}
|
|
9911
|
+
case "int": {
|
|
9912
|
+
const userNum = typeof userValue === "number" ? userValue : parseFloat(String(userValue));
|
|
9913
|
+
const expectedNum = parseFloat(expectedValue);
|
|
9914
|
+
if (isNaN(userNum) || isNaN(expectedNum)) {
|
|
9915
|
+
log(`TriggerManager: Invalid number comparison - userValue: ${userValue}, expected: ${expectedValue}`);
|
|
9916
|
+
return false;
|
|
9917
|
+
}
|
|
9918
|
+
return this.applyOperator(userNum, expectedNum, operator);
|
|
9919
|
+
}
|
|
9920
|
+
case "date": {
|
|
9921
|
+
const userDate = userValue instanceof Date ? userValue : new Date(String(userValue));
|
|
9922
|
+
const expectedDate = new Date(expectedValue);
|
|
9923
|
+
if (isNaN(userDate.getTime()) || isNaN(expectedDate.getTime())) {
|
|
9924
|
+
log(`TriggerManager: Invalid date comparison - userValue: ${userValue}, expected: ${expectedValue}`);
|
|
9925
|
+
return false;
|
|
9926
|
+
}
|
|
9927
|
+
return this.applyOperator(userDate.getTime(), expectedDate.getTime(), operator);
|
|
9928
|
+
}
|
|
9929
|
+
default:
|
|
9930
|
+
log(`TriggerManager: Unknown attribute type: ${attributeType}`);
|
|
9931
|
+
return false;
|
|
9932
|
+
}
|
|
9933
|
+
} catch (error2) {
|
|
9934
|
+
return false;
|
|
9935
|
+
}
|
|
9936
|
+
}
|
|
9937
|
+
/**
|
|
9938
|
+
* Applies the comparison operator to two values
|
|
9939
|
+
*/
|
|
9940
|
+
applyOperator(userValue, expectedValue, operator) {
|
|
9941
|
+
switch (operator) {
|
|
9942
|
+
case "equals":
|
|
9943
|
+
return userValue === expectedValue;
|
|
9944
|
+
case "notEquals":
|
|
9945
|
+
return userValue !== expectedValue;
|
|
9946
|
+
case "greaterThan":
|
|
9947
|
+
return userValue > expectedValue;
|
|
9948
|
+
case "lessThan":
|
|
9949
|
+
return userValue < expectedValue;
|
|
9950
|
+
default:
|
|
9951
|
+
return false;
|
|
9952
|
+
}
|
|
9953
|
+
}
|
|
9750
9954
|
/**
|
|
9751
9955
|
* Sets up click event listeners for all playlists with elementClicked triggers
|
|
9752
9956
|
*/
|
|
@@ -11787,7 +11991,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
11787
11991
|
__proto__: null,
|
|
11788
11992
|
SaltfishPlayer
|
|
11789
11993
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
11790
|
-
const version = "0.3.
|
|
11994
|
+
const version = "0.3.41";
|
|
11791
11995
|
const packageJson = {
|
|
11792
11996
|
version
|
|
11793
11997
|
};
|