@syntrologie/adapt-overlays 2.4.0 → 2.5.1
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/WorkflowTracker.d.ts +10 -0
- package/dist/WorkflowTracker.d.ts.map +1 -0
- package/dist/WorkflowTracker.js +19 -0
- package/dist/WorkflowWidget.d.ts +70 -0
- package/dist/WorkflowWidget.d.ts.map +1 -0
- package/dist/WorkflowWidget.js +329 -0
- package/dist/cdn.d.ts +2 -2
- package/dist/celebrations/__tests__/engine.test.d.ts +2 -0
- package/dist/celebrations/__tests__/engine.test.d.ts.map +1 -0
- package/dist/celebrations/__tests__/engine.test.js +130 -0
- package/dist/celebrations/__tests__/executor.test.d.ts +2 -0
- package/dist/celebrations/__tests__/executor.test.d.ts.map +1 -0
- package/dist/celebrations/__tests__/executor.test.js +102 -0
- package/dist/celebrations/effects/__tests__/confetti.test.d.ts +2 -0
- package/dist/celebrations/effects/__tests__/confetti.test.d.ts.map +1 -0
- package/dist/celebrations/effects/__tests__/confetti.test.js +89 -0
- package/dist/celebrations/effects/__tests__/emoji-rain.test.d.ts +2 -0
- package/dist/celebrations/effects/__tests__/emoji-rain.test.d.ts.map +1 -0
- package/dist/celebrations/effects/__tests__/emoji-rain.test.js +88 -0
- package/dist/celebrations/effects/__tests__/fireworks.test.d.ts +2 -0
- package/dist/celebrations/effects/__tests__/fireworks.test.d.ts.map +1 -0
- package/dist/celebrations/effects/__tests__/fireworks.test.js +87 -0
- package/dist/celebrations/effects/__tests__/sparkles.test.d.ts +2 -0
- package/dist/celebrations/effects/__tests__/sparkles.test.d.ts.map +1 -0
- package/dist/celebrations/effects/__tests__/sparkles.test.js +79 -0
- package/dist/celebrations/effects/confetti.d.ts +3 -0
- package/dist/celebrations/effects/confetti.d.ts.map +1 -0
- package/dist/celebrations/effects/confetti.js +80 -0
- package/dist/celebrations/effects/emoji-rain.d.ts +3 -0
- package/dist/celebrations/effects/emoji-rain.d.ts.map +1 -0
- package/dist/celebrations/effects/emoji-rain.js +73 -0
- package/dist/celebrations/effects/fireworks.d.ts +3 -0
- package/dist/celebrations/effects/fireworks.d.ts.map +1 -0
- package/dist/celebrations/effects/fireworks.js +69 -0
- package/dist/celebrations/effects/sparkles.d.ts +3 -0
- package/dist/celebrations/effects/sparkles.d.ts.map +1 -0
- package/dist/celebrations/effects/sparkles.js +83 -0
- package/dist/celebrations/engine.d.ts +16 -0
- package/dist/celebrations/engine.d.ts.map +1 -0
- package/dist/celebrations/engine.js +89 -0
- package/dist/celebrations/index.d.ts +3 -0
- package/dist/celebrations/index.d.ts.map +1 -0
- package/dist/celebrations/index.js +73 -0
- package/dist/celebrations/types.d.ts +34 -0
- package/dist/celebrations/types.d.ts.map +1 -0
- package/dist/celebrations/types.js +1 -0
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +59 -5
- package/dist/executors/tour.d.ts +20 -0
- package/dist/executors/tour.d.ts.map +1 -0
- package/dist/executors/tour.js +335 -0
- package/dist/modal.d.ts +2 -0
- package/dist/modal.d.ts.map +1 -1
- package/dist/modal.js +18 -8
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +141 -24
- package/dist/schema.d.ts +684 -4
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +36 -0
- package/dist/summarize.d.ts.map +1 -1
- package/dist/summarize.js +15 -4
- package/dist/tooltip.d.ts.map +1 -1
- package/dist/tooltip.js +26 -12
- package/dist/tour-types.d.ts +34 -0
- package/dist/tour-types.d.ts.map +1 -0
- package/dist/tour-types.js +7 -0
- package/dist/types.d.ts +20 -85
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-types.d.ts +15 -0
- package/dist/workflow-types.d.ts.map +1 -0
- package/dist/workflow-types.js +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.js +224 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.js +102 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.js +58 -6
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.js +18 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.js +61 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.js +478 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.js +54 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.js +257 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.js +1015 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts +4 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.js +2 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts +2 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.js +20 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts +10 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +350 -87
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts +3 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.js +5 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts +24 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/{useShowWhenStatus.js → useTriggerWhenStatus.js} +18 -15
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +3 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -1
- package/package.json +3 -2
- package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +0 -26
- package/node_modules/@syntrologie/sdk-contracts/dist/index.js +0 -13
- package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +0 -1428
- package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +0 -142
- package/node_modules/@syntrologie/sdk-contracts/package.json +0 -33
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useShowWhenStatus.d.ts +0 -24
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useShowWhenStatus.d.ts.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const PARTICLES_PER_BURST = { light: 20, medium: 40, heavy: 80 };
|
|
2
|
+
const BURST_COUNTS = { light: 3, medium: 4, heavy: 5 };
|
|
3
|
+
export const fireworksEffect = {
|
|
4
|
+
init(width, height, config) {
|
|
5
|
+
const perBurst = PARTICLES_PER_BURST[config.intensity];
|
|
6
|
+
const burstCount = BURST_COUNTS[config.intensity];
|
|
7
|
+
const colors = config.colors.length > 0 ? config.colors : ['#ff4444', '#44ff44', '#4444ff'];
|
|
8
|
+
const particles = [];
|
|
9
|
+
for (let b = 0; b < burstCount; b++) {
|
|
10
|
+
const cx = Math.random() * width * 0.8 + width * 0.1;
|
|
11
|
+
const cy = Math.random() * height * 0.6;
|
|
12
|
+
const burstColor = colors[Math.floor(Math.random() * colors.length)];
|
|
13
|
+
for (let i = 0; i < perBurst; i++) {
|
|
14
|
+
const angle = (Math.PI * 2 * i) / perBurst + (Math.random() - 0.5) * 0.3;
|
|
15
|
+
const speed = Math.random() * 3 + 2;
|
|
16
|
+
particles.push({
|
|
17
|
+
x: cx,
|
|
18
|
+
y: cy,
|
|
19
|
+
vx: Math.cos(angle) * speed,
|
|
20
|
+
vy: Math.sin(angle) * speed,
|
|
21
|
+
rotation: 0,
|
|
22
|
+
rotationSpeed: 0,
|
|
23
|
+
size: Math.random() * 3 + 2,
|
|
24
|
+
color: burstColor,
|
|
25
|
+
opacity: 1,
|
|
26
|
+
shape: 'circle',
|
|
27
|
+
data: { centerX: cx, centerY: cy },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return particles;
|
|
32
|
+
},
|
|
33
|
+
update(particles, _dt, _elapsed) {
|
|
34
|
+
let anyVisible = false;
|
|
35
|
+
for (const p of particles) {
|
|
36
|
+
// Deceleration
|
|
37
|
+
p.vx *= 0.97;
|
|
38
|
+
p.vy *= 0.97;
|
|
39
|
+
// Slight gravity
|
|
40
|
+
p.vy += 0.03;
|
|
41
|
+
// Movement
|
|
42
|
+
p.x += p.vx;
|
|
43
|
+
p.y += p.vy;
|
|
44
|
+
// Fade over time
|
|
45
|
+
p.opacity -= 0.008;
|
|
46
|
+
if (p.opacity < 0)
|
|
47
|
+
p.opacity = 0;
|
|
48
|
+
if (p.opacity > 0.01) {
|
|
49
|
+
anyVisible = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return anyVisible;
|
|
53
|
+
},
|
|
54
|
+
render(ctx, particles) {
|
|
55
|
+
for (const p of particles) {
|
|
56
|
+
if (p.opacity < 0.01)
|
|
57
|
+
continue;
|
|
58
|
+
ctx.save();
|
|
59
|
+
ctx.globalAlpha = p.opacity;
|
|
60
|
+
ctx.fillStyle = p.color;
|
|
61
|
+
ctx.shadowBlur = 12;
|
|
62
|
+
ctx.shadowColor = p.color;
|
|
63
|
+
ctx.beginPath();
|
|
64
|
+
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
|
|
65
|
+
ctx.fill();
|
|
66
|
+
ctx.restore();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparkles.d.ts","sourceRoot":"","sources":["../../../src/celebrations/effects/sparkles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,iBAAiB,EAAY,MAAM,UAAU,CAAC;AAI/E,eAAO,MAAM,cAAc,EAAE,iBA0F5B,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const INTENSITY_COUNTS = { light: 30, medium: 60, heavy: 120 };
|
|
2
|
+
export const sparklesEffect = {
|
|
3
|
+
init(width, height, config) {
|
|
4
|
+
const count = INTENSITY_COUNTS[config.intensity];
|
|
5
|
+
const colors = config.colors.length > 0 ? config.colors : ['#ffd700', '#ffffff', '#fffacd'];
|
|
6
|
+
const particles = [];
|
|
7
|
+
for (let i = 0; i < count; i++) {
|
|
8
|
+
particles.push({
|
|
9
|
+
x: Math.random() * width,
|
|
10
|
+
y: Math.random() * height,
|
|
11
|
+
vx: (Math.random() - 0.5) * 0.3,
|
|
12
|
+
vy: -(Math.random() * 0.5 + 0.2),
|
|
13
|
+
rotation: Math.random() * Math.PI * 2,
|
|
14
|
+
rotationSpeed: (Math.random() - 0.5) * 0.1,
|
|
15
|
+
size: Math.random() * 4 + 2,
|
|
16
|
+
color: colors[Math.floor(Math.random() * colors.length)],
|
|
17
|
+
opacity: Math.random() * 0.5 + 0.5,
|
|
18
|
+
shape: 'circle',
|
|
19
|
+
data: {
|
|
20
|
+
/** Phase offset for sine-wave twinkle */
|
|
21
|
+
phase: Math.random() * Math.PI * 2,
|
|
22
|
+
/** Base opacity before twinkle modulation */
|
|
23
|
+
baseOpacity: Math.random() * 0.5 + 0.5,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return particles;
|
|
28
|
+
},
|
|
29
|
+
update(particles, _dt, elapsed) {
|
|
30
|
+
let anyVisible = false;
|
|
31
|
+
for (const p of particles) {
|
|
32
|
+
// Gentle upward float
|
|
33
|
+
p.x += p.vx;
|
|
34
|
+
p.y += p.vy;
|
|
35
|
+
p.rotation += p.rotationSpeed;
|
|
36
|
+
// Gradually fade out over lifetime
|
|
37
|
+
if (p.data) {
|
|
38
|
+
p.data.baseOpacity = (p.data.baseOpacity ?? 1) - 0.001;
|
|
39
|
+
if (p.data.baseOpacity < 0)
|
|
40
|
+
p.data.baseOpacity = 0;
|
|
41
|
+
}
|
|
42
|
+
// Twinkle — oscillate opacity with sine wave
|
|
43
|
+
const phase = p.data?.phase ?? 0;
|
|
44
|
+
const baseOpacity = p.data?.baseOpacity ?? 1;
|
|
45
|
+
if (baseOpacity <= 0.01) {
|
|
46
|
+
p.opacity = 0;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const twinkle = Math.sin(elapsed * 0.005 + phase) * 0.4 + 0.6;
|
|
50
|
+
p.opacity = baseOpacity * twinkle;
|
|
51
|
+
}
|
|
52
|
+
if (p.opacity > 0.01) {
|
|
53
|
+
anyVisible = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return anyVisible;
|
|
57
|
+
},
|
|
58
|
+
render(ctx, particles) {
|
|
59
|
+
for (const p of particles) {
|
|
60
|
+
if (p.opacity < 0.01)
|
|
61
|
+
continue;
|
|
62
|
+
ctx.save();
|
|
63
|
+
ctx.globalAlpha = p.opacity;
|
|
64
|
+
ctx.fillStyle = p.color;
|
|
65
|
+
ctx.translate(p.x, p.y);
|
|
66
|
+
ctx.rotate(p.rotation);
|
|
67
|
+
// Draw a 4-point diamond/star shape
|
|
68
|
+
const s = p.size;
|
|
69
|
+
ctx.beginPath();
|
|
70
|
+
ctx.moveTo(0, -s);
|
|
71
|
+
ctx.lineTo(s * 0.3, -s * 0.3);
|
|
72
|
+
ctx.lineTo(s, 0);
|
|
73
|
+
ctx.lineTo(s * 0.3, s * 0.3);
|
|
74
|
+
ctx.lineTo(0, s);
|
|
75
|
+
ctx.lineTo(-s * 0.3, s * 0.3);
|
|
76
|
+
ctx.lineTo(-s, 0);
|
|
77
|
+
ctx.lineTo(-s * 0.3, -s * 0.3);
|
|
78
|
+
ctx.closePath();
|
|
79
|
+
ctx.fill();
|
|
80
|
+
ctx.restore();
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CelebrationConfig, CelebrationEffect } from './types';
|
|
2
|
+
export declare class CelebrationEngine {
|
|
3
|
+
private canvas;
|
|
4
|
+
private ctx;
|
|
5
|
+
private rafId;
|
|
6
|
+
private particles;
|
|
7
|
+
private startTime;
|
|
8
|
+
private lastFrame;
|
|
9
|
+
private duration;
|
|
10
|
+
private effect;
|
|
11
|
+
private container;
|
|
12
|
+
start(container: HTMLElement, effect: CelebrationEffect, config: CelebrationConfig): void;
|
|
13
|
+
stop(): void;
|
|
14
|
+
private tick;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/celebrations/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAY,MAAM,SAAS,CAAC;AAE9E,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,GAAG,CAAyC;IACpD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,SAAS,CAA4B;IAE7C,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IA2CzF,IAAI,IAAI,IAAI;IAeZ,OAAO,CAAC,IAAI;CA+Bb"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export class CelebrationEngine {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.canvas = null;
|
|
4
|
+
this.ctx = null;
|
|
5
|
+
this.rafId = null;
|
|
6
|
+
this.particles = [];
|
|
7
|
+
this.startTime = 0;
|
|
8
|
+
this.lastFrame = 0;
|
|
9
|
+
this.duration = 0;
|
|
10
|
+
this.effect = null;
|
|
11
|
+
this.container = null;
|
|
12
|
+
}
|
|
13
|
+
start(container, effect, config) {
|
|
14
|
+
this.container = container;
|
|
15
|
+
this.effect = effect;
|
|
16
|
+
this.duration = config.duration;
|
|
17
|
+
// Create fullscreen canvas
|
|
18
|
+
const canvas = document.createElement('canvas');
|
|
19
|
+
canvas.setAttribute('data-syntro-celebrate', '');
|
|
20
|
+
Object.assign(canvas.style, {
|
|
21
|
+
position: 'fixed',
|
|
22
|
+
inset: '0',
|
|
23
|
+
pointerEvents: 'none',
|
|
24
|
+
zIndex: '2147483646',
|
|
25
|
+
});
|
|
26
|
+
const dpr = window.devicePixelRatio || 1;
|
|
27
|
+
const width = window.innerWidth;
|
|
28
|
+
const height = window.innerHeight;
|
|
29
|
+
canvas.width = width * dpr;
|
|
30
|
+
canvas.height = height * dpr;
|
|
31
|
+
canvas.style.width = `${width}px`;
|
|
32
|
+
canvas.style.height = `${height}px`;
|
|
33
|
+
const ctx = canvas.getContext('2d');
|
|
34
|
+
if (!ctx) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
ctx.scale(dpr, dpr);
|
|
38
|
+
this.canvas = canvas;
|
|
39
|
+
this.ctx = ctx;
|
|
40
|
+
container.appendChild(canvas);
|
|
41
|
+
// Initialize particles
|
|
42
|
+
this.particles = effect.init(width, height, config);
|
|
43
|
+
this.startTime = performance.now();
|
|
44
|
+
this.lastFrame = this.startTime;
|
|
45
|
+
// Start animation loop
|
|
46
|
+
this.tick = this.tick.bind(this);
|
|
47
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
48
|
+
}
|
|
49
|
+
stop() {
|
|
50
|
+
if (this.rafId !== null) {
|
|
51
|
+
cancelAnimationFrame(this.rafId);
|
|
52
|
+
this.rafId = null;
|
|
53
|
+
}
|
|
54
|
+
if (this.canvas && this.container) {
|
|
55
|
+
this.canvas.remove();
|
|
56
|
+
this.canvas = null;
|
|
57
|
+
}
|
|
58
|
+
this.ctx = null;
|
|
59
|
+
this.effect = null;
|
|
60
|
+
this.container = null;
|
|
61
|
+
this.particles = [];
|
|
62
|
+
}
|
|
63
|
+
tick(now) {
|
|
64
|
+
if (!this.ctx || !this.canvas || !this.effect)
|
|
65
|
+
return;
|
|
66
|
+
const elapsed = now - this.startTime;
|
|
67
|
+
const dt = now - this.lastFrame;
|
|
68
|
+
this.lastFrame = now;
|
|
69
|
+
// Auto-stop after duration
|
|
70
|
+
if (elapsed >= this.duration) {
|
|
71
|
+
this.stop();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Clear canvas
|
|
75
|
+
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
|
76
|
+
const height = this.canvas.height / (window.devicePixelRatio || 1);
|
|
77
|
+
this.ctx.clearRect(0, 0, width, height);
|
|
78
|
+
// Update physics — stop if all particles are done
|
|
79
|
+
const alive = this.effect.update(this.particles, dt, elapsed);
|
|
80
|
+
if (!alive) {
|
|
81
|
+
this.stop();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Render
|
|
85
|
+
this.effect.render(this.ctx, this.particles);
|
|
86
|
+
// Next frame
|
|
87
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/celebrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAkB,MAAM,UAAU,CAAC;AAoDhF,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,eAAe,CAoC5D,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { confettiEffect } from './effects/confetti';
|
|
2
|
+
import { emojiRainEffect } from './effects/emoji-rain';
|
|
3
|
+
import { fireworksEffect } from './effects/fireworks';
|
|
4
|
+
import { sparklesEffect } from './effects/sparkles';
|
|
5
|
+
import { CelebrationEngine } from './engine';
|
|
6
|
+
const FALLBACK_COLORS = [
|
|
7
|
+
'#ff0000',
|
|
8
|
+
'#00ff00',
|
|
9
|
+
'#0000ff',
|
|
10
|
+
'#ffff00',
|
|
11
|
+
'#ff00ff',
|
|
12
|
+
'#00ffff',
|
|
13
|
+
'#ff8800',
|
|
14
|
+
'#8800ff',
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Build a celebration palette from the theme's primary/hover colors.
|
|
18
|
+
* Returns 6 color variants (solid, transparent, white accent) for visual variety.
|
|
19
|
+
*/
|
|
20
|
+
function buildThemePalette(primary, hover) {
|
|
21
|
+
return [primary, hover, `${primary}cc`, `${hover}cc`, '#ffffff', `${primary}80`];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read --sc-color-primary and --sc-color-primary-hover from the overlay root.
|
|
25
|
+
* Returns a theme palette if both are available, otherwise null.
|
|
26
|
+
*/
|
|
27
|
+
function readThemeColors(overlayRoot) {
|
|
28
|
+
try {
|
|
29
|
+
const styles = getComputedStyle(overlayRoot);
|
|
30
|
+
const primary = styles.getPropertyValue('--sc-color-primary')?.trim();
|
|
31
|
+
const hover = styles.getPropertyValue('--sc-color-primary-hover')?.trim();
|
|
32
|
+
if (primary?.startsWith('#') && primary.length >= 7) {
|
|
33
|
+
return buildThemePalette(primary, hover || primary);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* fallback */
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const effectRegistry = new Map([
|
|
42
|
+
['confetti', confettiEffect],
|
|
43
|
+
['fireworks', fireworksEffect],
|
|
44
|
+
['sparkles', sparklesEffect],
|
|
45
|
+
['emoji-rain', emojiRainEffect],
|
|
46
|
+
]);
|
|
47
|
+
export const executeCelebrate = async (action, context) => {
|
|
48
|
+
const effect = effectRegistry.get(action.effect);
|
|
49
|
+
if (!effect) {
|
|
50
|
+
console.warn(`[adaptive-overlays] Unknown celebration effect: "${action.effect}". Available: ${[...effectRegistry.keys()].join(', ')}`);
|
|
51
|
+
return { cleanup: () => { } };
|
|
52
|
+
}
|
|
53
|
+
// Colors priority: action.colors > theme palette > hardcoded fallback
|
|
54
|
+
const colors = action.colors ?? readThemeColors(context.overlayRoot) ?? FALLBACK_COLORS;
|
|
55
|
+
const config = {
|
|
56
|
+
duration: action.duration ?? 3000,
|
|
57
|
+
intensity: action.intensity ?? 'medium',
|
|
58
|
+
colors,
|
|
59
|
+
props: action.props,
|
|
60
|
+
};
|
|
61
|
+
const engine = new CelebrationEngine();
|
|
62
|
+
engine.start(context.overlayRoot, effect, config);
|
|
63
|
+
context.publishEvent('action.applied', {
|
|
64
|
+
id: context.generateId(),
|
|
65
|
+
kind: 'overlays:celebrate',
|
|
66
|
+
effect: action.effect,
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
cleanup: () => {
|
|
70
|
+
engine.stop();
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** A single particle in the animation */
|
|
2
|
+
export interface Particle {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
vx: number;
|
|
6
|
+
vy: number;
|
|
7
|
+
rotation: number;
|
|
8
|
+
rotationSpeed: number;
|
|
9
|
+
size: number;
|
|
10
|
+
color: string;
|
|
11
|
+
opacity: number;
|
|
12
|
+
shape?: 'rect' | 'circle' | 'emoji';
|
|
13
|
+
emoji?: string;
|
|
14
|
+
/** Effect-specific extra data */
|
|
15
|
+
data?: Record<string, number>;
|
|
16
|
+
}
|
|
17
|
+
/** Shared config props passed to all effects */
|
|
18
|
+
export interface CelebrationConfig {
|
|
19
|
+
duration: number;
|
|
20
|
+
intensity: 'light' | 'medium' | 'heavy';
|
|
21
|
+
colors: string[];
|
|
22
|
+
/** Effect-specific props (emoji string, burst point, etc.) */
|
|
23
|
+
props?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/** The pluggable effect interface — init/update/render */
|
|
26
|
+
export interface CelebrationEffect {
|
|
27
|
+
/** Create initial particles */
|
|
28
|
+
init(width: number, height: number, config: CelebrationConfig): Particle[];
|
|
29
|
+
/** Update particle physics each frame. Return false when all particles are done. */
|
|
30
|
+
update(particles: Particle[], dt: number, elapsed: number): boolean;
|
|
31
|
+
/** Draw particles to canvas */
|
|
32
|
+
render(ctx: CanvasRenderingContext2D, particles: Particle[]): void;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/celebrations/types.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,QAAQ,EAAE,CAAC;IAC3E,oFAAoF;IACpF,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACpE,+BAA+B;IAC/B,MAAM,CAAC,GAAG,EAAE,wBAAwB,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;CACpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/editor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqBH,OAAO,KAAK,EAAE,gBAAgB,EAAY,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqBH,OAAO,KAAK,EAAE,gBAAgB,EAAY,MAAM,SAAS,CAAC;AA4N1D,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,gBAAgB,2CAif5E;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;CAAe,CAAC;AAExC,eAAe,cAAc,CAAC"}
|
package/dist/editor.js
CHANGED
|
@@ -10,6 +10,39 @@ import { DetectionBadge, DismissedSection, EditorBody, EditorCard, EditorFooter,
|
|
|
10
10
|
import { MessageSquare, Route, Sparkles, Square, Tag, Zap } from 'lucide-react';
|
|
11
11
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
12
12
|
import { summarizeOverlayItem } from './summarize';
|
|
13
|
+
/** Extract the CSS selector string from an anchorId (object or legacy string). */
|
|
14
|
+
function resolveAnchorSelector(anchorId) {
|
|
15
|
+
if (!anchorId)
|
|
16
|
+
return '';
|
|
17
|
+
if (typeof anchorId === 'string')
|
|
18
|
+
return anchorId;
|
|
19
|
+
if (typeof anchorId === 'object' && 'selector' in anchorId) {
|
|
20
|
+
return anchorId.selector;
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
/** Extract the target route from an AnchorId object, ignoring wildcard '**'. */
|
|
25
|
+
function resolveAnchorRoute(anchorId) {
|
|
26
|
+
if (!anchorId || typeof anchorId !== 'object')
|
|
27
|
+
return null;
|
|
28
|
+
const route = anchorId.route;
|
|
29
|
+
if (typeof route === 'string' && route !== '**')
|
|
30
|
+
return route;
|
|
31
|
+
if (Array.isArray(route)) {
|
|
32
|
+
const first = route.find((r) => typeof r === 'string' && r !== '**');
|
|
33
|
+
return first ?? null;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/** Save a pending highlight selector to sessionStorage (inlined to avoid cross-package import). */
|
|
38
|
+
function savePendingHighlight(selector) {
|
|
39
|
+
try {
|
|
40
|
+
sessionStorage.setItem('syntro:editor:pending-highlight', selector);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Silently ignore
|
|
44
|
+
}
|
|
45
|
+
}
|
|
13
46
|
function itemKey(section, index) {
|
|
14
47
|
return `${section}:${index}`;
|
|
15
48
|
}
|
|
@@ -41,7 +74,8 @@ function flattenItems(config) {
|
|
|
41
74
|
section,
|
|
42
75
|
index: i,
|
|
43
76
|
summary: summarizeOverlayItem(section, rec),
|
|
44
|
-
anchorId: rec.anchorId
|
|
77
|
+
anchorId: resolveAnchorSelector(rec.anchorId),
|
|
78
|
+
rawAnchorId: rec.anchorId,
|
|
45
79
|
isTour: false,
|
|
46
80
|
});
|
|
47
81
|
});
|
|
@@ -55,6 +89,7 @@ function flattenItems(config) {
|
|
|
55
89
|
index: i,
|
|
56
90
|
summary: summarizeOverlayItem('tours', tour),
|
|
57
91
|
anchorId: '',
|
|
92
|
+
rawAnchorId: undefined,
|
|
58
93
|
isTour: true,
|
|
59
94
|
});
|
|
60
95
|
});
|
|
@@ -89,7 +124,7 @@ function getStepIcon(step) {
|
|
|
89
124
|
}
|
|
90
125
|
function getStepLabel(step) {
|
|
91
126
|
const action = step.action;
|
|
92
|
-
const anchor = action.anchorId;
|
|
127
|
+
const anchor = resolveAnchorSelector(action.anchorId);
|
|
93
128
|
if (anchor)
|
|
94
129
|
return anchor;
|
|
95
130
|
const content = action.content;
|
|
@@ -117,7 +152,7 @@ function useAnchorDetection(items, config) {
|
|
|
117
152
|
if (tour && tour.steps.length > 0) {
|
|
118
153
|
const firstStep = tour.steps[0];
|
|
119
154
|
const action = firstStep.action;
|
|
120
|
-
selectorToCheck = action?.anchorId
|
|
155
|
+
selectorToCheck = resolveAnchorSelector(action?.anchorId);
|
|
121
156
|
}
|
|
122
157
|
}
|
|
123
158
|
if (!selectorToCheck) {
|
|
@@ -274,6 +309,25 @@ export function OverlaysEditor({ config, onChange, editor }) {
|
|
|
274
309
|
}
|
|
275
310
|
editor.publish();
|
|
276
311
|
}, [dismissedKeys, typedConfig, onChange, editor]);
|
|
312
|
+
const handleBadgeClick = useCallback(async (item) => {
|
|
313
|
+
const detection = detectionMap.get(item.key);
|
|
314
|
+
if (detection?.found && item.anchorId) {
|
|
315
|
+
editor.highlightElement(item.anchorId);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
const route = resolveAnchorRoute(item.rawAnchorId);
|
|
319
|
+
if (route) {
|
|
320
|
+
if (item.anchorId)
|
|
321
|
+
savePendingHighlight(item.anchorId);
|
|
322
|
+
await editor.navigateTo(route);
|
|
323
|
+
if (item.anchorId)
|
|
324
|
+
editor.highlightElement(item.anchorId);
|
|
325
|
+
}
|
|
326
|
+
else if (item.anchorId) {
|
|
327
|
+
editor.highlightElement(item.anchorId);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}, [editor, detectionMap]);
|
|
277
331
|
const handleCardHover = useCallback((item) => {
|
|
278
332
|
setHoveredKey(item.key);
|
|
279
333
|
if (item.anchorId) {
|
|
@@ -290,7 +344,7 @@ export function OverlaysEditor({ config, onChange, editor }) {
|
|
|
290
344
|
const item = arr[index];
|
|
291
345
|
if (!item)
|
|
292
346
|
return null;
|
|
293
|
-
const anchorId = item.anchorId
|
|
347
|
+
const anchorId = resolveAnchorSelector(item.anchorId);
|
|
294
348
|
switch (section) {
|
|
295
349
|
case 'tooltips': {
|
|
296
350
|
const content = item.content || {};
|
|
@@ -343,7 +397,7 @@ export function OverlaysEditor({ config, onChange, editor }) {
|
|
|
343
397
|
};
|
|
344
398
|
const renderCard = (item) => {
|
|
345
399
|
const detection = detectionMap.get(item.key);
|
|
346
|
-
return (_jsxs("div", { children: [_jsxs(EditorCard, { itemKey: item.key, onClick: () => handleCardClick(item), className: "se-flex se-items-center se-gap-2", onMouseEnter: () => handleCardHover(item), onMouseLeave: handleCardLeave, children: [_jsx(DetectionBadge, { found: detection?.found ?? false }), _jsx("span", { className: "se-shrink-0 se-flex se-items-center -se-ml-1", onClick: (e) => {
|
|
400
|
+
return (_jsxs("div", { children: [_jsxs(EditorCard, { itemKey: item.key, onClick: () => handleCardClick(item), className: "se-flex se-items-center se-gap-2", onMouseEnter: () => handleCardHover(item), onMouseLeave: handleCardLeave, children: [_jsx(DetectionBadge, { found: detection?.found ?? false, onClick: () => handleBadgeClick(item) }), _jsx("span", { className: "se-shrink-0 se-flex se-items-center -se-ml-1", onClick: (e) => {
|
|
347
401
|
e.stopPropagation();
|
|
348
402
|
handleCardClick(item);
|
|
349
403
|
}, children: _jsx(SectionIcon, { section: item.section }) }), _jsx("span", { className: "se-flex-1 se-overflow-hidden se-text-ellipsis se-whitespace-nowrap", onClick: () => handleCardClick(item), children: item.summary }), _jsx("button", { type: "button", className: "se-py-0.5 se-px-1.5 se-rounded se-border-none se-bg-transparent se-text-slate-grey-7 se-text-sm se-cursor-pointer se-shrink-0 se-leading-none", onClick: (e) => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tour Executor
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates sequential tour steps with cross-page state persistence.
|
|
5
|
+
* Tours can span multiple pages and resume after navigation.
|
|
6
|
+
*
|
|
7
|
+
* Each step contains an inner action (modal, tooltip) that gets executed.
|
|
8
|
+
* The tour listens for CTA click events to advance to the next step.
|
|
9
|
+
*/
|
|
10
|
+
import type { ActionExecutor } from '@syntrologie/sdk-contracts';
|
|
11
|
+
import type { TourAction } from '../tour-types';
|
|
12
|
+
/**
|
|
13
|
+
* Execute a tour action
|
|
14
|
+
*
|
|
15
|
+
* Tours orchestrate a sequence of steps, persisting state to localStorage
|
|
16
|
+
* to support cross-page navigation. Each step contains an action to execute
|
|
17
|
+
* and optionally defines transitions based on action events.
|
|
18
|
+
*/
|
|
19
|
+
export declare const executeTour: ActionExecutor<TourAction>;
|
|
20
|
+
//# sourceMappingURL=tour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tour.d.ts","sourceRoot":"","sources":["../../src/executors/tour.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAmC,MAAM,4BAA4B,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,eAAe,CAAC;AAiG1D;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,UAAU,CAwSlD,CAAC"}
|