@eventop/sdk 1.2.15 → 1.3.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/core.cjs +157 -2
- package/dist/core.js +157 -2
- package/dist/react/core.cjs +157 -2
- package/dist/react/core.js +157 -2
- package/package.json +1 -1
package/dist/core.cjs
CHANGED
|
@@ -221,6 +221,71 @@ function injectStyles(theme, pos) {
|
|
|
221
221
|
style.textContent = `
|
|
222
222
|
#sai-trigger, #sai-panel { ${buildCSSVars(theme)} }
|
|
223
223
|
|
|
224
|
+
/* ── Ring Light Animation ── */
|
|
225
|
+
@keyframes sai-ring-pulse {
|
|
226
|
+
0% {
|
|
227
|
+
box-shadow:
|
|
228
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.7),
|
|
229
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.5),
|
|
230
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.3);
|
|
231
|
+
}
|
|
232
|
+
50% {
|
|
233
|
+
box-shadow:
|
|
234
|
+
0 0 0 8px rgba(var(--sai-accent-rgb), 0),
|
|
235
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0.3),
|
|
236
|
+
0 0 0 24px rgba(var(--sai-accent-rgb), 0);
|
|
237
|
+
}
|
|
238
|
+
100% {
|
|
239
|
+
box-shadow:
|
|
240
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0),
|
|
241
|
+
0 0 0 32px rgba(var(--sai-accent-rgb), 0),
|
|
242
|
+
0 0 0 48px rgba(var(--sai-accent-rgb), 0);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@keyframes sai-ring-pulse-hard {
|
|
247
|
+
0% {
|
|
248
|
+
box-shadow:
|
|
249
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
250
|
+
0 0 0 3px var(--sai-accent),
|
|
251
|
+
0 0 20px var(--sai-accent);
|
|
252
|
+
}
|
|
253
|
+
50% {
|
|
254
|
+
box-shadow:
|
|
255
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
256
|
+
0 0 0 8px var(--sai-accent),
|
|
257
|
+
0 0 40px var(--sai-accent);
|
|
258
|
+
}
|
|
259
|
+
100% {
|
|
260
|
+
box-shadow:
|
|
261
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
262
|
+
0 0 0 3px var(--sai-accent),
|
|
263
|
+
0 0 20px var(--sai-accent);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
@keyframes sai-element-highlight {
|
|
268
|
+
0% { filter: brightness(1); }
|
|
269
|
+
50% { filter: brightness(1.15); }
|
|
270
|
+
100% { filter: brightness(1); }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Highlighted element styles */
|
|
274
|
+
.sai-highlighted {
|
|
275
|
+
position: relative !important;
|
|
276
|
+
animation: sai-ring-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
277
|
+
z-index: 99997 !important;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.sai-highlighted.sai-highlight-hard {
|
|
281
|
+
animation: sai-ring-pulse-hard 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.sai-highlighted.sai-highlight-subtle {
|
|
285
|
+
animation: sai-element-highlight 2s ease-in-out infinite !important;
|
|
286
|
+
filter: drop-shadow(0 0 8px var(--sai-accent)) !important;
|
|
287
|
+
}
|
|
288
|
+
|
|
224
289
|
/* ── Trigger ── */
|
|
225
290
|
#sai-trigger {
|
|
226
291
|
position: fixed; ${triggerCSS};
|
|
@@ -1006,6 +1071,7 @@ function expandFlowSteps(aiStep, feature) {
|
|
|
1006
1071
|
|
|
1007
1072
|
// Loads Shepherd.js, builds + runs tours, wires up advanceOn listeners,
|
|
1008
1073
|
// progress indicators, pause/resume, and step-level error display.
|
|
1074
|
+
// ENHANCED: Adds animated ring light effect to highlighted elements.
|
|
1009
1075
|
|
|
1010
1076
|
const SHEPHERD_JS = 'https://cdn.jsdelivr.net/npm/shepherd.js@11.2.0/dist/js/shepherd.min.js';
|
|
1011
1077
|
|
|
@@ -1026,6 +1092,61 @@ async function ensureShepherd() {
|
|
|
1026
1092
|
await loadScript(SHEPHERD_JS);
|
|
1027
1093
|
}
|
|
1028
1094
|
|
|
1095
|
+
// ─── Highlight management ────────────────────────────────────────────────────
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Applies the ring light animation to an element.
|
|
1099
|
+
*
|
|
1100
|
+
* @param {HTMLElement} el
|
|
1101
|
+
* @param {string} [style='default'] - 'default' | 'hard' | 'subtle'
|
|
1102
|
+
*/
|
|
1103
|
+
function applyHighlight(el, style = 'default') {
|
|
1104
|
+
if (!el) return;
|
|
1105
|
+
|
|
1106
|
+
// Set CSS variables for accent color parsing in RGB format
|
|
1107
|
+
const accentColor = getComputedStyle(el).getPropertyValue('--sai-accent') || '#e94560';
|
|
1108
|
+
const rgb = hexToRgb(accentColor.trim());
|
|
1109
|
+
if (rgb) {
|
|
1110
|
+
el.style.setProperty('--sai-accent-rgb', `${rgb.r}, ${rgb.g}, ${rgb.b}`);
|
|
1111
|
+
}
|
|
1112
|
+
el.classList.add('sai-highlighted');
|
|
1113
|
+
if (style === 'hard') {
|
|
1114
|
+
el.classList.add('sai-highlight-hard');
|
|
1115
|
+
} else if (style === 'subtle') {
|
|
1116
|
+
el.classList.add('sai-highlight-subtle');
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Scroll into view with extra padding
|
|
1120
|
+
if (el.scrollIntoView) {
|
|
1121
|
+
el.scrollIntoView({
|
|
1122
|
+
behavior: 'smooth',
|
|
1123
|
+
block: 'center'
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Removes the ring light animation from an element.
|
|
1130
|
+
*/
|
|
1131
|
+
function removeHighlight(el) {
|
|
1132
|
+
if (!el) return;
|
|
1133
|
+
el.classList.remove('sai-highlighted', 'sai-highlight-hard', 'sai-highlight-subtle');
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Converts hex color to RGB object.
|
|
1138
|
+
* @param {string} hex
|
|
1139
|
+
* @returns {object|null}
|
|
1140
|
+
*/
|
|
1141
|
+
function hexToRgb(hex) {
|
|
1142
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
1143
|
+
return result ? {
|
|
1144
|
+
r: parseInt(result[1], 16),
|
|
1145
|
+
g: parseInt(result[2], 16),
|
|
1146
|
+
b: parseInt(result[3], 16)
|
|
1147
|
+
} : null;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1029
1150
|
// ─── Feature-map merge ────────────────────────────────────────────────────────
|
|
1030
1151
|
|
|
1031
1152
|
/**
|
|
@@ -1059,6 +1180,7 @@ function mergeWithFeature(step) {
|
|
|
1059
1180
|
* 1. Cross-page navigation (route prop) with automatic waiting
|
|
1060
1181
|
* 2. Legacy screen navigation (screen.navigate)
|
|
1061
1182
|
* 3. Element waiting (waitFor prop)
|
|
1183
|
+
* 4. Ring light animation application
|
|
1062
1184
|
*
|
|
1063
1185
|
* @param {object} step
|
|
1064
1186
|
* @param {number} waitTimeout
|
|
@@ -1082,6 +1204,10 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1082
1204
|
});
|
|
1083
1205
|
} catch (_) {/* non-fatal */}
|
|
1084
1206
|
await waitForElement(postNavMerge.selector, waitTimeout);
|
|
1207
|
+
|
|
1208
|
+
// Apply ring light animation to the element
|
|
1209
|
+
const el = document.querySelector(postNavMerge.selector);
|
|
1210
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1085
1211
|
return;
|
|
1086
1212
|
}
|
|
1087
1213
|
}
|
|
@@ -1091,6 +1217,12 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1091
1217
|
if (freshMerged.waitFor) {
|
|
1092
1218
|
await waitForElement(freshMerged.waitFor, waitTimeout);
|
|
1093
1219
|
}
|
|
1220
|
+
|
|
1221
|
+
// Apply ring light animation to the main selector
|
|
1222
|
+
if (freshMerged.selector) {
|
|
1223
|
+
const el = document.querySelector(freshMerged.selector);
|
|
1224
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1225
|
+
}
|
|
1094
1226
|
})();
|
|
1095
1227
|
}
|
|
1096
1228
|
|
|
@@ -1139,11 +1271,13 @@ function addProgressIndicator(shepherdStep, index, total) {
|
|
|
1139
1271
|
|
|
1140
1272
|
/**
|
|
1141
1273
|
* Starts a Shepherd tour from the given steps array.
|
|
1274
|
+
* ENHANCED: Applies ring light animations to highlighted elements.
|
|
1142
1275
|
*
|
|
1143
1276
|
* @param {Array} steps
|
|
1144
1277
|
* @param {object} [options]
|
|
1145
1278
|
* @param {boolean} [options.showProgress=true]
|
|
1146
1279
|
* @param {number} [options.waitTimeout=8000]
|
|
1280
|
+
* @param {string} [options.highlightStyle='default'] - 'default' | 'hard' | 'subtle'
|
|
1147
1281
|
*/
|
|
1148
1282
|
async function runTour(steps, options = {}) {
|
|
1149
1283
|
var _state$config2;
|
|
@@ -1156,9 +1290,13 @@ async function runTour(steps, options = {}) {
|
|
|
1156
1290
|
if (!(steps !== null && steps !== void 0 && steps.length)) return;
|
|
1157
1291
|
const {
|
|
1158
1292
|
showProgress = true,
|
|
1159
|
-
waitTimeout = 8000
|
|
1293
|
+
waitTimeout = 8000,
|
|
1294
|
+
highlightStyle = 'default'
|
|
1160
1295
|
} = options;
|
|
1161
|
-
const mergedSteps = steps.map(
|
|
1296
|
+
const mergedSteps = steps.map(step => ({
|
|
1297
|
+
...mergeWithFeature(step),
|
|
1298
|
+
_highlightStyle: highlightStyle
|
|
1299
|
+
}));
|
|
1162
1300
|
|
|
1163
1301
|
// Legacy: navigate to the correct screen for the first step
|
|
1164
1302
|
const firstFeature = (_state$config2 = config) === null || _state$config2 === void 0 || (_state$config2 = _state$config2.features) === null || _state$config2 === void 0 ? void 0 : _state$config2.find(f => {
|
|
@@ -1224,12 +1362,24 @@ async function runTour(steps, options = {}) {
|
|
|
1224
1362
|
});
|
|
1225
1363
|
step._shepherdRef = shepherdStep;
|
|
1226
1364
|
shepherdStep._isLast = isLast;
|
|
1365
|
+
|
|
1366
|
+
// Clean up highlight on hide
|
|
1367
|
+
shepherdStep.on('hide', () => {
|
|
1368
|
+
if (step.selector) {
|
|
1369
|
+
const el = document.querySelector(step.selector);
|
|
1370
|
+
if (el) removeHighlight(el);
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1227
1373
|
if (hasAuto) wireAdvanceOn(shepherdStep, step.advanceOn, tour$1);
|
|
1228
1374
|
if (showProgress && expandedSteps.length > 1) {
|
|
1229
1375
|
addProgressIndicator(shepherdStep, i, expandedSteps.length);
|
|
1230
1376
|
}
|
|
1231
1377
|
});
|
|
1232
1378
|
tour$1.on('complete', () => {
|
|
1379
|
+
// Clean up all highlights
|
|
1380
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1381
|
+
removeHighlight(el);
|
|
1382
|
+
});
|
|
1233
1383
|
runAndClearCleanups();
|
|
1234
1384
|
setPausedSteps(null);
|
|
1235
1385
|
setPausedIndex(0);
|
|
@@ -1240,6 +1390,11 @@ async function runTour(steps, options = {}) {
|
|
|
1240
1390
|
tour$1.on('cancel', () => {
|
|
1241
1391
|
const currentStepEl = tour$1.getCurrentStep();
|
|
1242
1392
|
const currentIdx = currentStepEl ? expandedSteps.findIndex(s => s.id === currentStepEl.id) : 0;
|
|
1393
|
+
|
|
1394
|
+
// Clean up all highlights
|
|
1395
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1396
|
+
removeHighlight(el);
|
|
1397
|
+
});
|
|
1243
1398
|
runAndClearCleanups();
|
|
1244
1399
|
setPausedSteps(expandedSteps);
|
|
1245
1400
|
setPausedIndex(Math.max(0, currentIdx));
|
package/dist/core.js
CHANGED
|
@@ -219,6 +219,71 @@ function injectStyles(theme, pos) {
|
|
|
219
219
|
style.textContent = `
|
|
220
220
|
#sai-trigger, #sai-panel { ${buildCSSVars(theme)} }
|
|
221
221
|
|
|
222
|
+
/* ── Ring Light Animation ── */
|
|
223
|
+
@keyframes sai-ring-pulse {
|
|
224
|
+
0% {
|
|
225
|
+
box-shadow:
|
|
226
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.7),
|
|
227
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.5),
|
|
228
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.3);
|
|
229
|
+
}
|
|
230
|
+
50% {
|
|
231
|
+
box-shadow:
|
|
232
|
+
0 0 0 8px rgba(var(--sai-accent-rgb), 0),
|
|
233
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0.3),
|
|
234
|
+
0 0 0 24px rgba(var(--sai-accent-rgb), 0);
|
|
235
|
+
}
|
|
236
|
+
100% {
|
|
237
|
+
box-shadow:
|
|
238
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0),
|
|
239
|
+
0 0 0 32px rgba(var(--sai-accent-rgb), 0),
|
|
240
|
+
0 0 0 48px rgba(var(--sai-accent-rgb), 0);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@keyframes sai-ring-pulse-hard {
|
|
245
|
+
0% {
|
|
246
|
+
box-shadow:
|
|
247
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
248
|
+
0 0 0 3px var(--sai-accent),
|
|
249
|
+
0 0 20px var(--sai-accent);
|
|
250
|
+
}
|
|
251
|
+
50% {
|
|
252
|
+
box-shadow:
|
|
253
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
254
|
+
0 0 0 8px var(--sai-accent),
|
|
255
|
+
0 0 40px var(--sai-accent);
|
|
256
|
+
}
|
|
257
|
+
100% {
|
|
258
|
+
box-shadow:
|
|
259
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
260
|
+
0 0 0 3px var(--sai-accent),
|
|
261
|
+
0 0 20px var(--sai-accent);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@keyframes sai-element-highlight {
|
|
266
|
+
0% { filter: brightness(1); }
|
|
267
|
+
50% { filter: brightness(1.15); }
|
|
268
|
+
100% { filter: brightness(1); }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Highlighted element styles */
|
|
272
|
+
.sai-highlighted {
|
|
273
|
+
position: relative !important;
|
|
274
|
+
animation: sai-ring-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
275
|
+
z-index: 99997 !important;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.sai-highlighted.sai-highlight-hard {
|
|
279
|
+
animation: sai-ring-pulse-hard 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.sai-highlighted.sai-highlight-subtle {
|
|
283
|
+
animation: sai-element-highlight 2s ease-in-out infinite !important;
|
|
284
|
+
filter: drop-shadow(0 0 8px var(--sai-accent)) !important;
|
|
285
|
+
}
|
|
286
|
+
|
|
222
287
|
/* ── Trigger ── */
|
|
223
288
|
#sai-trigger {
|
|
224
289
|
position: fixed; ${triggerCSS};
|
|
@@ -1004,6 +1069,7 @@ function expandFlowSteps(aiStep, feature) {
|
|
|
1004
1069
|
|
|
1005
1070
|
// Loads Shepherd.js, builds + runs tours, wires up advanceOn listeners,
|
|
1006
1071
|
// progress indicators, pause/resume, and step-level error display.
|
|
1072
|
+
// ENHANCED: Adds animated ring light effect to highlighted elements.
|
|
1007
1073
|
|
|
1008
1074
|
const SHEPHERD_JS = 'https://cdn.jsdelivr.net/npm/shepherd.js@11.2.0/dist/js/shepherd.min.js';
|
|
1009
1075
|
|
|
@@ -1024,6 +1090,61 @@ async function ensureShepherd() {
|
|
|
1024
1090
|
await loadScript(SHEPHERD_JS);
|
|
1025
1091
|
}
|
|
1026
1092
|
|
|
1093
|
+
// ─── Highlight management ────────────────────────────────────────────────────
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Applies the ring light animation to an element.
|
|
1097
|
+
*
|
|
1098
|
+
* @param {HTMLElement} el
|
|
1099
|
+
* @param {string} [style='default'] - 'default' | 'hard' | 'subtle'
|
|
1100
|
+
*/
|
|
1101
|
+
function applyHighlight(el, style = 'default') {
|
|
1102
|
+
if (!el) return;
|
|
1103
|
+
|
|
1104
|
+
// Set CSS variables for accent color parsing in RGB format
|
|
1105
|
+
const accentColor = getComputedStyle(el).getPropertyValue('--sai-accent') || '#e94560';
|
|
1106
|
+
const rgb = hexToRgb(accentColor.trim());
|
|
1107
|
+
if (rgb) {
|
|
1108
|
+
el.style.setProperty('--sai-accent-rgb', `${rgb.r}, ${rgb.g}, ${rgb.b}`);
|
|
1109
|
+
}
|
|
1110
|
+
el.classList.add('sai-highlighted');
|
|
1111
|
+
if (style === 'hard') {
|
|
1112
|
+
el.classList.add('sai-highlight-hard');
|
|
1113
|
+
} else if (style === 'subtle') {
|
|
1114
|
+
el.classList.add('sai-highlight-subtle');
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Scroll into view with extra padding
|
|
1118
|
+
if (el.scrollIntoView) {
|
|
1119
|
+
el.scrollIntoView({
|
|
1120
|
+
behavior: 'smooth',
|
|
1121
|
+
block: 'center'
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Removes the ring light animation from an element.
|
|
1128
|
+
*/
|
|
1129
|
+
function removeHighlight(el) {
|
|
1130
|
+
if (!el) return;
|
|
1131
|
+
el.classList.remove('sai-highlighted', 'sai-highlight-hard', 'sai-highlight-subtle');
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* Converts hex color to RGB object.
|
|
1136
|
+
* @param {string} hex
|
|
1137
|
+
* @returns {object|null}
|
|
1138
|
+
*/
|
|
1139
|
+
function hexToRgb(hex) {
|
|
1140
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
1141
|
+
return result ? {
|
|
1142
|
+
r: parseInt(result[1], 16),
|
|
1143
|
+
g: parseInt(result[2], 16),
|
|
1144
|
+
b: parseInt(result[3], 16)
|
|
1145
|
+
} : null;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1027
1148
|
// ─── Feature-map merge ────────────────────────────────────────────────────────
|
|
1028
1149
|
|
|
1029
1150
|
/**
|
|
@@ -1057,6 +1178,7 @@ function mergeWithFeature(step) {
|
|
|
1057
1178
|
* 1. Cross-page navigation (route prop) with automatic waiting
|
|
1058
1179
|
* 2. Legacy screen navigation (screen.navigate)
|
|
1059
1180
|
* 3. Element waiting (waitFor prop)
|
|
1181
|
+
* 4. Ring light animation application
|
|
1060
1182
|
*
|
|
1061
1183
|
* @param {object} step
|
|
1062
1184
|
* @param {number} waitTimeout
|
|
@@ -1080,6 +1202,10 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1080
1202
|
});
|
|
1081
1203
|
} catch (_) {/* non-fatal */}
|
|
1082
1204
|
await waitForElement(postNavMerge.selector, waitTimeout);
|
|
1205
|
+
|
|
1206
|
+
// Apply ring light animation to the element
|
|
1207
|
+
const el = document.querySelector(postNavMerge.selector);
|
|
1208
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1083
1209
|
return;
|
|
1084
1210
|
}
|
|
1085
1211
|
}
|
|
@@ -1089,6 +1215,12 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1089
1215
|
if (freshMerged.waitFor) {
|
|
1090
1216
|
await waitForElement(freshMerged.waitFor, waitTimeout);
|
|
1091
1217
|
}
|
|
1218
|
+
|
|
1219
|
+
// Apply ring light animation to the main selector
|
|
1220
|
+
if (freshMerged.selector) {
|
|
1221
|
+
const el = document.querySelector(freshMerged.selector);
|
|
1222
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1223
|
+
}
|
|
1092
1224
|
})();
|
|
1093
1225
|
}
|
|
1094
1226
|
|
|
@@ -1137,11 +1269,13 @@ function addProgressIndicator(shepherdStep, index, total) {
|
|
|
1137
1269
|
|
|
1138
1270
|
/**
|
|
1139
1271
|
* Starts a Shepherd tour from the given steps array.
|
|
1272
|
+
* ENHANCED: Applies ring light animations to highlighted elements.
|
|
1140
1273
|
*
|
|
1141
1274
|
* @param {Array} steps
|
|
1142
1275
|
* @param {object} [options]
|
|
1143
1276
|
* @param {boolean} [options.showProgress=true]
|
|
1144
1277
|
* @param {number} [options.waitTimeout=8000]
|
|
1278
|
+
* @param {string} [options.highlightStyle='default'] - 'default' | 'hard' | 'subtle'
|
|
1145
1279
|
*/
|
|
1146
1280
|
async function runTour(steps, options = {}) {
|
|
1147
1281
|
var _state$config2;
|
|
@@ -1154,9 +1288,13 @@ async function runTour(steps, options = {}) {
|
|
|
1154
1288
|
if (!(steps !== null && steps !== void 0 && steps.length)) return;
|
|
1155
1289
|
const {
|
|
1156
1290
|
showProgress = true,
|
|
1157
|
-
waitTimeout = 8000
|
|
1291
|
+
waitTimeout = 8000,
|
|
1292
|
+
highlightStyle = 'default'
|
|
1158
1293
|
} = options;
|
|
1159
|
-
const mergedSteps = steps.map(
|
|
1294
|
+
const mergedSteps = steps.map(step => ({
|
|
1295
|
+
...mergeWithFeature(step),
|
|
1296
|
+
_highlightStyle: highlightStyle
|
|
1297
|
+
}));
|
|
1160
1298
|
|
|
1161
1299
|
// Legacy: navigate to the correct screen for the first step
|
|
1162
1300
|
const firstFeature = (_state$config2 = config) === null || _state$config2 === void 0 || (_state$config2 = _state$config2.features) === null || _state$config2 === void 0 ? void 0 : _state$config2.find(f => {
|
|
@@ -1222,12 +1360,24 @@ async function runTour(steps, options = {}) {
|
|
|
1222
1360
|
});
|
|
1223
1361
|
step._shepherdRef = shepherdStep;
|
|
1224
1362
|
shepherdStep._isLast = isLast;
|
|
1363
|
+
|
|
1364
|
+
// Clean up highlight on hide
|
|
1365
|
+
shepherdStep.on('hide', () => {
|
|
1366
|
+
if (step.selector) {
|
|
1367
|
+
const el = document.querySelector(step.selector);
|
|
1368
|
+
if (el) removeHighlight(el);
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1225
1371
|
if (hasAuto) wireAdvanceOn(shepherdStep, step.advanceOn, tour$1);
|
|
1226
1372
|
if (showProgress && expandedSteps.length > 1) {
|
|
1227
1373
|
addProgressIndicator(shepherdStep, i, expandedSteps.length);
|
|
1228
1374
|
}
|
|
1229
1375
|
});
|
|
1230
1376
|
tour$1.on('complete', () => {
|
|
1377
|
+
// Clean up all highlights
|
|
1378
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1379
|
+
removeHighlight(el);
|
|
1380
|
+
});
|
|
1231
1381
|
runAndClearCleanups();
|
|
1232
1382
|
setPausedSteps(null);
|
|
1233
1383
|
setPausedIndex(0);
|
|
@@ -1238,6 +1388,11 @@ async function runTour(steps, options = {}) {
|
|
|
1238
1388
|
tour$1.on('cancel', () => {
|
|
1239
1389
|
const currentStepEl = tour$1.getCurrentStep();
|
|
1240
1390
|
const currentIdx = currentStepEl ? expandedSteps.findIndex(s => s.id === currentStepEl.id) : 0;
|
|
1391
|
+
|
|
1392
|
+
// Clean up all highlights
|
|
1393
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1394
|
+
removeHighlight(el);
|
|
1395
|
+
});
|
|
1241
1396
|
runAndClearCleanups();
|
|
1242
1397
|
setPausedSteps(expandedSteps);
|
|
1243
1398
|
setPausedIndex(Math.max(0, currentIdx));
|
package/dist/react/core.cjs
CHANGED
|
@@ -221,6 +221,71 @@ function injectStyles(theme, pos) {
|
|
|
221
221
|
style.textContent = `
|
|
222
222
|
#sai-trigger, #sai-panel { ${buildCSSVars(theme)} }
|
|
223
223
|
|
|
224
|
+
/* ── Ring Light Animation ── */
|
|
225
|
+
@keyframes sai-ring-pulse {
|
|
226
|
+
0% {
|
|
227
|
+
box-shadow:
|
|
228
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.7),
|
|
229
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.5),
|
|
230
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.3);
|
|
231
|
+
}
|
|
232
|
+
50% {
|
|
233
|
+
box-shadow:
|
|
234
|
+
0 0 0 8px rgba(var(--sai-accent-rgb), 0),
|
|
235
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0.3),
|
|
236
|
+
0 0 0 24px rgba(var(--sai-accent-rgb), 0);
|
|
237
|
+
}
|
|
238
|
+
100% {
|
|
239
|
+
box-shadow:
|
|
240
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0),
|
|
241
|
+
0 0 0 32px rgba(var(--sai-accent-rgb), 0),
|
|
242
|
+
0 0 0 48px rgba(var(--sai-accent-rgb), 0);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@keyframes sai-ring-pulse-hard {
|
|
247
|
+
0% {
|
|
248
|
+
box-shadow:
|
|
249
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
250
|
+
0 0 0 3px var(--sai-accent),
|
|
251
|
+
0 0 20px var(--sai-accent);
|
|
252
|
+
}
|
|
253
|
+
50% {
|
|
254
|
+
box-shadow:
|
|
255
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
256
|
+
0 0 0 8px var(--sai-accent),
|
|
257
|
+
0 0 40px var(--sai-accent);
|
|
258
|
+
}
|
|
259
|
+
100% {
|
|
260
|
+
box-shadow:
|
|
261
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
262
|
+
0 0 0 3px var(--sai-accent),
|
|
263
|
+
0 0 20px var(--sai-accent);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
@keyframes sai-element-highlight {
|
|
268
|
+
0% { filter: brightness(1); }
|
|
269
|
+
50% { filter: brightness(1.15); }
|
|
270
|
+
100% { filter: brightness(1); }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Highlighted element styles */
|
|
274
|
+
.sai-highlighted {
|
|
275
|
+
position: relative !important;
|
|
276
|
+
animation: sai-ring-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
277
|
+
z-index: 99997 !important;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.sai-highlighted.sai-highlight-hard {
|
|
281
|
+
animation: sai-ring-pulse-hard 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.sai-highlighted.sai-highlight-subtle {
|
|
285
|
+
animation: sai-element-highlight 2s ease-in-out infinite !important;
|
|
286
|
+
filter: drop-shadow(0 0 8px var(--sai-accent)) !important;
|
|
287
|
+
}
|
|
288
|
+
|
|
224
289
|
/* ── Trigger ── */
|
|
225
290
|
#sai-trigger {
|
|
226
291
|
position: fixed; ${triggerCSS};
|
|
@@ -1006,6 +1071,7 @@ function expandFlowSteps(aiStep, feature) {
|
|
|
1006
1071
|
|
|
1007
1072
|
// Loads Shepherd.js, builds + runs tours, wires up advanceOn listeners,
|
|
1008
1073
|
// progress indicators, pause/resume, and step-level error display.
|
|
1074
|
+
// ENHANCED: Adds animated ring light effect to highlighted elements.
|
|
1009
1075
|
|
|
1010
1076
|
const SHEPHERD_JS = 'https://cdn.jsdelivr.net/npm/shepherd.js@11.2.0/dist/js/shepherd.min.js';
|
|
1011
1077
|
|
|
@@ -1026,6 +1092,61 @@ async function ensureShepherd() {
|
|
|
1026
1092
|
await loadScript(SHEPHERD_JS);
|
|
1027
1093
|
}
|
|
1028
1094
|
|
|
1095
|
+
// ─── Highlight management ────────────────────────────────────────────────────
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Applies the ring light animation to an element.
|
|
1099
|
+
*
|
|
1100
|
+
* @param {HTMLElement} el
|
|
1101
|
+
* @param {string} [style='default'] - 'default' | 'hard' | 'subtle'
|
|
1102
|
+
*/
|
|
1103
|
+
function applyHighlight(el, style = 'default') {
|
|
1104
|
+
if (!el) return;
|
|
1105
|
+
|
|
1106
|
+
// Set CSS variables for accent color parsing in RGB format
|
|
1107
|
+
const accentColor = getComputedStyle(el).getPropertyValue('--sai-accent') || '#e94560';
|
|
1108
|
+
const rgb = hexToRgb(accentColor.trim());
|
|
1109
|
+
if (rgb) {
|
|
1110
|
+
el.style.setProperty('--sai-accent-rgb', `${rgb.r}, ${rgb.g}, ${rgb.b}`);
|
|
1111
|
+
}
|
|
1112
|
+
el.classList.add('sai-highlighted');
|
|
1113
|
+
if (style === 'hard') {
|
|
1114
|
+
el.classList.add('sai-highlight-hard');
|
|
1115
|
+
} else if (style === 'subtle') {
|
|
1116
|
+
el.classList.add('sai-highlight-subtle');
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Scroll into view with extra padding
|
|
1120
|
+
if (el.scrollIntoView) {
|
|
1121
|
+
el.scrollIntoView({
|
|
1122
|
+
behavior: 'smooth',
|
|
1123
|
+
block: 'center'
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Removes the ring light animation from an element.
|
|
1130
|
+
*/
|
|
1131
|
+
function removeHighlight(el) {
|
|
1132
|
+
if (!el) return;
|
|
1133
|
+
el.classList.remove('sai-highlighted', 'sai-highlight-hard', 'sai-highlight-subtle');
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Converts hex color to RGB object.
|
|
1138
|
+
* @param {string} hex
|
|
1139
|
+
* @returns {object|null}
|
|
1140
|
+
*/
|
|
1141
|
+
function hexToRgb(hex) {
|
|
1142
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
1143
|
+
return result ? {
|
|
1144
|
+
r: parseInt(result[1], 16),
|
|
1145
|
+
g: parseInt(result[2], 16),
|
|
1146
|
+
b: parseInt(result[3], 16)
|
|
1147
|
+
} : null;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1029
1150
|
// ─── Feature-map merge ────────────────────────────────────────────────────────
|
|
1030
1151
|
|
|
1031
1152
|
/**
|
|
@@ -1059,6 +1180,7 @@ function mergeWithFeature(step) {
|
|
|
1059
1180
|
* 1. Cross-page navigation (route prop) with automatic waiting
|
|
1060
1181
|
* 2. Legacy screen navigation (screen.navigate)
|
|
1061
1182
|
* 3. Element waiting (waitFor prop)
|
|
1183
|
+
* 4. Ring light animation application
|
|
1062
1184
|
*
|
|
1063
1185
|
* @param {object} step
|
|
1064
1186
|
* @param {number} waitTimeout
|
|
@@ -1082,6 +1204,10 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1082
1204
|
});
|
|
1083
1205
|
} catch (_) {/* non-fatal */}
|
|
1084
1206
|
await waitForElement(postNavMerge.selector, waitTimeout);
|
|
1207
|
+
|
|
1208
|
+
// Apply ring light animation to the element
|
|
1209
|
+
const el = document.querySelector(postNavMerge.selector);
|
|
1210
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1085
1211
|
return;
|
|
1086
1212
|
}
|
|
1087
1213
|
}
|
|
@@ -1091,6 +1217,12 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1091
1217
|
if (freshMerged.waitFor) {
|
|
1092
1218
|
await waitForElement(freshMerged.waitFor, waitTimeout);
|
|
1093
1219
|
}
|
|
1220
|
+
|
|
1221
|
+
// Apply ring light animation to the main selector
|
|
1222
|
+
if (freshMerged.selector) {
|
|
1223
|
+
const el = document.querySelector(freshMerged.selector);
|
|
1224
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1225
|
+
}
|
|
1094
1226
|
})();
|
|
1095
1227
|
}
|
|
1096
1228
|
|
|
@@ -1139,11 +1271,13 @@ function addProgressIndicator(shepherdStep, index, total) {
|
|
|
1139
1271
|
|
|
1140
1272
|
/**
|
|
1141
1273
|
* Starts a Shepherd tour from the given steps array.
|
|
1274
|
+
* ENHANCED: Applies ring light animations to highlighted elements.
|
|
1142
1275
|
*
|
|
1143
1276
|
* @param {Array} steps
|
|
1144
1277
|
* @param {object} [options]
|
|
1145
1278
|
* @param {boolean} [options.showProgress=true]
|
|
1146
1279
|
* @param {number} [options.waitTimeout=8000]
|
|
1280
|
+
* @param {string} [options.highlightStyle='default'] - 'default' | 'hard' | 'subtle'
|
|
1147
1281
|
*/
|
|
1148
1282
|
async function runTour(steps, options = {}) {
|
|
1149
1283
|
var _state$config2;
|
|
@@ -1156,9 +1290,13 @@ async function runTour(steps, options = {}) {
|
|
|
1156
1290
|
if (!(steps !== null && steps !== void 0 && steps.length)) return;
|
|
1157
1291
|
const {
|
|
1158
1292
|
showProgress = true,
|
|
1159
|
-
waitTimeout = 8000
|
|
1293
|
+
waitTimeout = 8000,
|
|
1294
|
+
highlightStyle = 'default'
|
|
1160
1295
|
} = options;
|
|
1161
|
-
const mergedSteps = steps.map(
|
|
1296
|
+
const mergedSteps = steps.map(step => ({
|
|
1297
|
+
...mergeWithFeature(step),
|
|
1298
|
+
_highlightStyle: highlightStyle
|
|
1299
|
+
}));
|
|
1162
1300
|
|
|
1163
1301
|
// Legacy: navigate to the correct screen for the first step
|
|
1164
1302
|
const firstFeature = (_state$config2 = config) === null || _state$config2 === void 0 || (_state$config2 = _state$config2.features) === null || _state$config2 === void 0 ? void 0 : _state$config2.find(f => {
|
|
@@ -1224,12 +1362,24 @@ async function runTour(steps, options = {}) {
|
|
|
1224
1362
|
});
|
|
1225
1363
|
step._shepherdRef = shepherdStep;
|
|
1226
1364
|
shepherdStep._isLast = isLast;
|
|
1365
|
+
|
|
1366
|
+
// Clean up highlight on hide
|
|
1367
|
+
shepherdStep.on('hide', () => {
|
|
1368
|
+
if (step.selector) {
|
|
1369
|
+
const el = document.querySelector(step.selector);
|
|
1370
|
+
if (el) removeHighlight(el);
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1227
1373
|
if (hasAuto) wireAdvanceOn(shepherdStep, step.advanceOn, tour$1);
|
|
1228
1374
|
if (showProgress && expandedSteps.length > 1) {
|
|
1229
1375
|
addProgressIndicator(shepherdStep, i, expandedSteps.length);
|
|
1230
1376
|
}
|
|
1231
1377
|
});
|
|
1232
1378
|
tour$1.on('complete', () => {
|
|
1379
|
+
// Clean up all highlights
|
|
1380
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1381
|
+
removeHighlight(el);
|
|
1382
|
+
});
|
|
1233
1383
|
runAndClearCleanups();
|
|
1234
1384
|
setPausedSteps(null);
|
|
1235
1385
|
setPausedIndex(0);
|
|
@@ -1240,6 +1390,11 @@ async function runTour(steps, options = {}) {
|
|
|
1240
1390
|
tour$1.on('cancel', () => {
|
|
1241
1391
|
const currentStepEl = tour$1.getCurrentStep();
|
|
1242
1392
|
const currentIdx = currentStepEl ? expandedSteps.findIndex(s => s.id === currentStepEl.id) : 0;
|
|
1393
|
+
|
|
1394
|
+
// Clean up all highlights
|
|
1395
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1396
|
+
removeHighlight(el);
|
|
1397
|
+
});
|
|
1243
1398
|
runAndClearCleanups();
|
|
1244
1399
|
setPausedSteps(expandedSteps);
|
|
1245
1400
|
setPausedIndex(Math.max(0, currentIdx));
|
package/dist/react/core.js
CHANGED
|
@@ -219,6 +219,71 @@ function injectStyles(theme, pos) {
|
|
|
219
219
|
style.textContent = `
|
|
220
220
|
#sai-trigger, #sai-panel { ${buildCSSVars(theme)} }
|
|
221
221
|
|
|
222
|
+
/* ── Ring Light Animation ── */
|
|
223
|
+
@keyframes sai-ring-pulse {
|
|
224
|
+
0% {
|
|
225
|
+
box-shadow:
|
|
226
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.7),
|
|
227
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.5),
|
|
228
|
+
0 0 0 0 rgba(var(--sai-accent-rgb), 0.3);
|
|
229
|
+
}
|
|
230
|
+
50% {
|
|
231
|
+
box-shadow:
|
|
232
|
+
0 0 0 8px rgba(var(--sai-accent-rgb), 0),
|
|
233
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0.3),
|
|
234
|
+
0 0 0 24px rgba(var(--sai-accent-rgb), 0);
|
|
235
|
+
}
|
|
236
|
+
100% {
|
|
237
|
+
box-shadow:
|
|
238
|
+
0 0 0 16px rgba(var(--sai-accent-rgb), 0),
|
|
239
|
+
0 0 0 32px rgba(var(--sai-accent-rgb), 0),
|
|
240
|
+
0 0 0 48px rgba(var(--sai-accent-rgb), 0);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@keyframes sai-ring-pulse-hard {
|
|
245
|
+
0% {
|
|
246
|
+
box-shadow:
|
|
247
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
248
|
+
0 0 0 3px var(--sai-accent),
|
|
249
|
+
0 0 20px var(--sai-accent);
|
|
250
|
+
}
|
|
251
|
+
50% {
|
|
252
|
+
box-shadow:
|
|
253
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
254
|
+
0 0 0 8px var(--sai-accent),
|
|
255
|
+
0 0 40px var(--sai-accent);
|
|
256
|
+
}
|
|
257
|
+
100% {
|
|
258
|
+
box-shadow:
|
|
259
|
+
inset 0 0 0 2px var(--sai-accent),
|
|
260
|
+
0 0 0 3px var(--sai-accent),
|
|
261
|
+
0 0 20px var(--sai-accent);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@keyframes sai-element-highlight {
|
|
266
|
+
0% { filter: brightness(1); }
|
|
267
|
+
50% { filter: brightness(1.15); }
|
|
268
|
+
100% { filter: brightness(1); }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Highlighted element styles */
|
|
272
|
+
.sai-highlighted {
|
|
273
|
+
position: relative !important;
|
|
274
|
+
animation: sai-ring-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
275
|
+
z-index: 99997 !important;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.sai-highlighted.sai-highlight-hard {
|
|
279
|
+
animation: sai-ring-pulse-hard 2s cubic-bezier(0.4, 0, 0.6, 1) infinite !important;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.sai-highlighted.sai-highlight-subtle {
|
|
283
|
+
animation: sai-element-highlight 2s ease-in-out infinite !important;
|
|
284
|
+
filter: drop-shadow(0 0 8px var(--sai-accent)) !important;
|
|
285
|
+
}
|
|
286
|
+
|
|
222
287
|
/* ── Trigger ── */
|
|
223
288
|
#sai-trigger {
|
|
224
289
|
position: fixed; ${triggerCSS};
|
|
@@ -1004,6 +1069,7 @@ function expandFlowSteps(aiStep, feature) {
|
|
|
1004
1069
|
|
|
1005
1070
|
// Loads Shepherd.js, builds + runs tours, wires up advanceOn listeners,
|
|
1006
1071
|
// progress indicators, pause/resume, and step-level error display.
|
|
1072
|
+
// ENHANCED: Adds animated ring light effect to highlighted elements.
|
|
1007
1073
|
|
|
1008
1074
|
const SHEPHERD_JS = 'https://cdn.jsdelivr.net/npm/shepherd.js@11.2.0/dist/js/shepherd.min.js';
|
|
1009
1075
|
|
|
@@ -1024,6 +1090,61 @@ async function ensureShepherd() {
|
|
|
1024
1090
|
await loadScript(SHEPHERD_JS);
|
|
1025
1091
|
}
|
|
1026
1092
|
|
|
1093
|
+
// ─── Highlight management ────────────────────────────────────────────────────
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Applies the ring light animation to an element.
|
|
1097
|
+
*
|
|
1098
|
+
* @param {HTMLElement} el
|
|
1099
|
+
* @param {string} [style='default'] - 'default' | 'hard' | 'subtle'
|
|
1100
|
+
*/
|
|
1101
|
+
function applyHighlight(el, style = 'default') {
|
|
1102
|
+
if (!el) return;
|
|
1103
|
+
|
|
1104
|
+
// Set CSS variables for accent color parsing in RGB format
|
|
1105
|
+
const accentColor = getComputedStyle(el).getPropertyValue('--sai-accent') || '#e94560';
|
|
1106
|
+
const rgb = hexToRgb(accentColor.trim());
|
|
1107
|
+
if (rgb) {
|
|
1108
|
+
el.style.setProperty('--sai-accent-rgb', `${rgb.r}, ${rgb.g}, ${rgb.b}`);
|
|
1109
|
+
}
|
|
1110
|
+
el.classList.add('sai-highlighted');
|
|
1111
|
+
if (style === 'hard') {
|
|
1112
|
+
el.classList.add('sai-highlight-hard');
|
|
1113
|
+
} else if (style === 'subtle') {
|
|
1114
|
+
el.classList.add('sai-highlight-subtle');
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Scroll into view with extra padding
|
|
1118
|
+
if (el.scrollIntoView) {
|
|
1119
|
+
el.scrollIntoView({
|
|
1120
|
+
behavior: 'smooth',
|
|
1121
|
+
block: 'center'
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Removes the ring light animation from an element.
|
|
1128
|
+
*/
|
|
1129
|
+
function removeHighlight(el) {
|
|
1130
|
+
if (!el) return;
|
|
1131
|
+
el.classList.remove('sai-highlighted', 'sai-highlight-hard', 'sai-highlight-subtle');
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* Converts hex color to RGB object.
|
|
1136
|
+
* @param {string} hex
|
|
1137
|
+
* @returns {object|null}
|
|
1138
|
+
*/
|
|
1139
|
+
function hexToRgb(hex) {
|
|
1140
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
1141
|
+
return result ? {
|
|
1142
|
+
r: parseInt(result[1], 16),
|
|
1143
|
+
g: parseInt(result[2], 16),
|
|
1144
|
+
b: parseInt(result[3], 16)
|
|
1145
|
+
} : null;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1027
1148
|
// ─── Feature-map merge ────────────────────────────────────────────────────────
|
|
1028
1149
|
|
|
1029
1150
|
/**
|
|
@@ -1057,6 +1178,7 @@ function mergeWithFeature(step) {
|
|
|
1057
1178
|
* 1. Cross-page navigation (route prop) with automatic waiting
|
|
1058
1179
|
* 2. Legacy screen navigation (screen.navigate)
|
|
1059
1180
|
* 3. Element waiting (waitFor prop)
|
|
1181
|
+
* 4. Ring light animation application
|
|
1060
1182
|
*
|
|
1061
1183
|
* @param {object} step
|
|
1062
1184
|
* @param {number} waitTimeout
|
|
@@ -1080,6 +1202,10 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1080
1202
|
});
|
|
1081
1203
|
} catch (_) {/* non-fatal */}
|
|
1082
1204
|
await waitForElement(postNavMerge.selector, waitTimeout);
|
|
1205
|
+
|
|
1206
|
+
// Apply ring light animation to the element
|
|
1207
|
+
const el = document.querySelector(postNavMerge.selector);
|
|
1208
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1083
1209
|
return;
|
|
1084
1210
|
}
|
|
1085
1211
|
}
|
|
@@ -1089,6 +1215,12 @@ function makeBeforeShowPromise(step, waitTimeout) {
|
|
|
1089
1215
|
if (freshMerged.waitFor) {
|
|
1090
1216
|
await waitForElement(freshMerged.waitFor, waitTimeout);
|
|
1091
1217
|
}
|
|
1218
|
+
|
|
1219
|
+
// Apply ring light animation to the main selector
|
|
1220
|
+
if (freshMerged.selector) {
|
|
1221
|
+
const el = document.querySelector(freshMerged.selector);
|
|
1222
|
+
if (el) applyHighlight(el, step._highlightStyle || 'default');
|
|
1223
|
+
}
|
|
1092
1224
|
})();
|
|
1093
1225
|
}
|
|
1094
1226
|
|
|
@@ -1137,11 +1269,13 @@ function addProgressIndicator(shepherdStep, index, total) {
|
|
|
1137
1269
|
|
|
1138
1270
|
/**
|
|
1139
1271
|
* Starts a Shepherd tour from the given steps array.
|
|
1272
|
+
* ENHANCED: Applies ring light animations to highlighted elements.
|
|
1140
1273
|
*
|
|
1141
1274
|
* @param {Array} steps
|
|
1142
1275
|
* @param {object} [options]
|
|
1143
1276
|
* @param {boolean} [options.showProgress=true]
|
|
1144
1277
|
* @param {number} [options.waitTimeout=8000]
|
|
1278
|
+
* @param {string} [options.highlightStyle='default'] - 'default' | 'hard' | 'subtle'
|
|
1145
1279
|
*/
|
|
1146
1280
|
async function runTour(steps, options = {}) {
|
|
1147
1281
|
var _state$config2;
|
|
@@ -1154,9 +1288,13 @@ async function runTour(steps, options = {}) {
|
|
|
1154
1288
|
if (!(steps !== null && steps !== void 0 && steps.length)) return;
|
|
1155
1289
|
const {
|
|
1156
1290
|
showProgress = true,
|
|
1157
|
-
waitTimeout = 8000
|
|
1291
|
+
waitTimeout = 8000,
|
|
1292
|
+
highlightStyle = 'default'
|
|
1158
1293
|
} = options;
|
|
1159
|
-
const mergedSteps = steps.map(
|
|
1294
|
+
const mergedSteps = steps.map(step => ({
|
|
1295
|
+
...mergeWithFeature(step),
|
|
1296
|
+
_highlightStyle: highlightStyle
|
|
1297
|
+
}));
|
|
1160
1298
|
|
|
1161
1299
|
// Legacy: navigate to the correct screen for the first step
|
|
1162
1300
|
const firstFeature = (_state$config2 = config) === null || _state$config2 === void 0 || (_state$config2 = _state$config2.features) === null || _state$config2 === void 0 ? void 0 : _state$config2.find(f => {
|
|
@@ -1222,12 +1360,24 @@ async function runTour(steps, options = {}) {
|
|
|
1222
1360
|
});
|
|
1223
1361
|
step._shepherdRef = shepherdStep;
|
|
1224
1362
|
shepherdStep._isLast = isLast;
|
|
1363
|
+
|
|
1364
|
+
// Clean up highlight on hide
|
|
1365
|
+
shepherdStep.on('hide', () => {
|
|
1366
|
+
if (step.selector) {
|
|
1367
|
+
const el = document.querySelector(step.selector);
|
|
1368
|
+
if (el) removeHighlight(el);
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1225
1371
|
if (hasAuto) wireAdvanceOn(shepherdStep, step.advanceOn, tour$1);
|
|
1226
1372
|
if (showProgress && expandedSteps.length > 1) {
|
|
1227
1373
|
addProgressIndicator(shepherdStep, i, expandedSteps.length);
|
|
1228
1374
|
}
|
|
1229
1375
|
});
|
|
1230
1376
|
tour$1.on('complete', () => {
|
|
1377
|
+
// Clean up all highlights
|
|
1378
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1379
|
+
removeHighlight(el);
|
|
1380
|
+
});
|
|
1231
1381
|
runAndClearCleanups();
|
|
1232
1382
|
setPausedSteps(null);
|
|
1233
1383
|
setPausedIndex(0);
|
|
@@ -1238,6 +1388,11 @@ async function runTour(steps, options = {}) {
|
|
|
1238
1388
|
tour$1.on('cancel', () => {
|
|
1239
1389
|
const currentStepEl = tour$1.getCurrentStep();
|
|
1240
1390
|
const currentIdx = currentStepEl ? expandedSteps.findIndex(s => s.id === currentStepEl.id) : 0;
|
|
1391
|
+
|
|
1392
|
+
// Clean up all highlights
|
|
1393
|
+
document.querySelectorAll('.sai-highlighted').forEach(el => {
|
|
1394
|
+
removeHighlight(el);
|
|
1395
|
+
});
|
|
1241
1396
|
runAndClearCleanups();
|
|
1242
1397
|
setPausedSteps(expandedSteps);
|
|
1243
1398
|
setPausedIndex(Math.max(0, currentIdx));
|