@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.
Files changed (118) hide show
  1. package/dist/WorkflowTracker.d.ts +10 -0
  2. package/dist/WorkflowTracker.d.ts.map +1 -0
  3. package/dist/WorkflowTracker.js +19 -0
  4. package/dist/WorkflowWidget.d.ts +70 -0
  5. package/dist/WorkflowWidget.d.ts.map +1 -0
  6. package/dist/WorkflowWidget.js +329 -0
  7. package/dist/cdn.d.ts +2 -2
  8. package/dist/celebrations/__tests__/engine.test.d.ts +2 -0
  9. package/dist/celebrations/__tests__/engine.test.d.ts.map +1 -0
  10. package/dist/celebrations/__tests__/engine.test.js +130 -0
  11. package/dist/celebrations/__tests__/executor.test.d.ts +2 -0
  12. package/dist/celebrations/__tests__/executor.test.d.ts.map +1 -0
  13. package/dist/celebrations/__tests__/executor.test.js +102 -0
  14. package/dist/celebrations/effects/__tests__/confetti.test.d.ts +2 -0
  15. package/dist/celebrations/effects/__tests__/confetti.test.d.ts.map +1 -0
  16. package/dist/celebrations/effects/__tests__/confetti.test.js +89 -0
  17. package/dist/celebrations/effects/__tests__/emoji-rain.test.d.ts +2 -0
  18. package/dist/celebrations/effects/__tests__/emoji-rain.test.d.ts.map +1 -0
  19. package/dist/celebrations/effects/__tests__/emoji-rain.test.js +88 -0
  20. package/dist/celebrations/effects/__tests__/fireworks.test.d.ts +2 -0
  21. package/dist/celebrations/effects/__tests__/fireworks.test.d.ts.map +1 -0
  22. package/dist/celebrations/effects/__tests__/fireworks.test.js +87 -0
  23. package/dist/celebrations/effects/__tests__/sparkles.test.d.ts +2 -0
  24. package/dist/celebrations/effects/__tests__/sparkles.test.d.ts.map +1 -0
  25. package/dist/celebrations/effects/__tests__/sparkles.test.js +79 -0
  26. package/dist/celebrations/effects/confetti.d.ts +3 -0
  27. package/dist/celebrations/effects/confetti.d.ts.map +1 -0
  28. package/dist/celebrations/effects/confetti.js +80 -0
  29. package/dist/celebrations/effects/emoji-rain.d.ts +3 -0
  30. package/dist/celebrations/effects/emoji-rain.d.ts.map +1 -0
  31. package/dist/celebrations/effects/emoji-rain.js +73 -0
  32. package/dist/celebrations/effects/fireworks.d.ts +3 -0
  33. package/dist/celebrations/effects/fireworks.d.ts.map +1 -0
  34. package/dist/celebrations/effects/fireworks.js +69 -0
  35. package/dist/celebrations/effects/sparkles.d.ts +3 -0
  36. package/dist/celebrations/effects/sparkles.d.ts.map +1 -0
  37. package/dist/celebrations/effects/sparkles.js +83 -0
  38. package/dist/celebrations/engine.d.ts +16 -0
  39. package/dist/celebrations/engine.d.ts.map +1 -0
  40. package/dist/celebrations/engine.js +89 -0
  41. package/dist/celebrations/index.d.ts +3 -0
  42. package/dist/celebrations/index.d.ts.map +1 -0
  43. package/dist/celebrations/index.js +73 -0
  44. package/dist/celebrations/types.d.ts +34 -0
  45. package/dist/celebrations/types.d.ts.map +1 -0
  46. package/dist/celebrations/types.js +1 -0
  47. package/dist/editor.d.ts.map +1 -1
  48. package/dist/editor.js +59 -5
  49. package/dist/executors/tour.d.ts +20 -0
  50. package/dist/executors/tour.d.ts.map +1 -0
  51. package/dist/executors/tour.js +335 -0
  52. package/dist/modal.d.ts +2 -0
  53. package/dist/modal.d.ts.map +1 -1
  54. package/dist/modal.js +18 -8
  55. package/dist/runtime.d.ts +25 -2
  56. package/dist/runtime.d.ts.map +1 -1
  57. package/dist/runtime.js +141 -24
  58. package/dist/schema.d.ts +684 -4
  59. package/dist/schema.d.ts.map +1 -1
  60. package/dist/schema.js +36 -0
  61. package/dist/summarize.d.ts.map +1 -1
  62. package/dist/summarize.js +15 -4
  63. package/dist/tooltip.d.ts.map +1 -1
  64. package/dist/tooltip.js +26 -12
  65. package/dist/tour-types.d.ts +34 -0
  66. package/dist/tour-types.d.ts.map +1 -0
  67. package/dist/tour-types.js +7 -0
  68. package/dist/types.d.ts +20 -85
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/workflow-types.d.ts +15 -0
  71. package/dist/workflow-types.d.ts.map +1 -0
  72. package/dist/workflow-types.js +1 -0
  73. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts +2 -0
  74. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts.map +1 -0
  75. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.js +224 -0
  76. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.js +102 -0
  77. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.js +58 -6
  78. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.js +18 -0
  79. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.js +61 -2
  80. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.js +478 -7
  81. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.js +54 -0
  82. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts +2 -0
  83. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts.map +1 -0
  84. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.js +257 -0
  85. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts +2 -0
  86. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts.map +1 -0
  87. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.js +1015 -0
  88. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +1 -1
  89. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts +4 -4
  90. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts.map +1 -1
  91. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.js +2 -2
  92. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts +2 -1
  93. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts.map +1 -1
  94. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.js +20 -3
  95. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts +10 -8
  96. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
  97. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +350 -87
  98. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.js +1 -1
  99. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts +3 -3
  100. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts.map +1 -1
  101. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.js +1 -1
  102. package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts +1 -1
  103. package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts.map +1 -1
  104. package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.js +5 -2
  105. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts +24 -0
  106. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +1 -0
  107. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/{useShowWhenStatus.js → useTriggerWhenStatus.js} +18 -15
  108. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +3 -3
  109. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
  110. package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -1
  111. package/package.json +3 -2
  112. package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +0 -26
  113. package/node_modules/@syntrologie/sdk-contracts/dist/index.js +0 -13
  114. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +0 -1428
  115. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +0 -142
  116. package/node_modules/@syntrologie/sdk-contracts/package.json +0 -33
  117. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useShowWhenStatus.d.ts +0 -24
  118. 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,3 @@
1
+ import type { CelebrationEffect } from '../types';
2
+ export declare const sparklesEffect: CelebrationEffect;
3
+ //# sourceMappingURL=sparkles.d.ts.map
@@ -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,3 @@
1
+ import type { ActionExecutor, CelebrateAction } from '../types';
2
+ export declare const executeCelebrate: ActionExecutor<CelebrateAction>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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 {};
@@ -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;AA0L1D,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,gBAAgB,2CA2d5E;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;CAAe,CAAC;AAExC,eAAe,cAAc,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"}