@syntrologie/adapt-content 2.8.0-canary.31 → 2.8.0-canary.310
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/runtime.d.ts.map +1 -1
- package/dist/runtime.js +431 -348
- package/dist/runtime.js.map +7 -0
- package/dist/schema.d.ts +56 -16
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +363 -62
- package/dist/schema.js.map +7 -0
- package/package.json +8 -26
- package/dist/cdn.d.ts +0 -35
- package/dist/cdn.d.ts.map +0 -1
- package/dist/cdn.js +0 -39
- package/dist/components/AnchorPicker.d.ts +0 -8
- package/dist/components/AnchorPicker.d.ts.map +0 -1
- package/dist/components/AnchorPicker.js +0 -6
- package/dist/content-editor-state.d.ts +0 -45
- package/dist/content-editor-state.d.ts.map +0 -1
- package/dist/content-editor-state.js +0 -123
- package/dist/content-editor-ui.d.ts +0 -26
- package/dist/content-editor-ui.d.ts.map +0 -1
- package/dist/content-editor-ui.js +0 -301
- package/dist/editor.d.ts +0 -9
- package/dist/editor.d.ts.map +0 -1
- package/dist/editor.js +0 -8
- package/dist/reconciliation-guard.js +0 -80
- package/dist/sanitizer.js +0 -95
- package/dist/summarize.js +0 -88
- package/dist/types.js +0 -7
- package/dist/utils/selectorGenerator.d.ts +0 -6
- package/dist/utils/selectorGenerator.d.ts.map +0 -1
- package/dist/utils/selectorGenerator.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/cn.d.ts +0 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/cn.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/cn.js +0 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.d.ts +0 -34
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +0 -158
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggle.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggle.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggle.js +0 -9
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts +0 -23
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.js +0 -40
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.js +0 -22
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSection.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSection.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSection.js +0 -9
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButton.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButton.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButton.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBody.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBody.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBody.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCard.d.ts +0 -13
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCard.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCard.js +0 -15
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooter.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooter.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooter.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeader.d.ts +0 -9
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeader.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeader.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInput.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInput.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInput.js +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayout.d.ts +0 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayout.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayout.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts +0 -25
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +0 -379
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelect.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelect.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelect.js +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextarea.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextarea.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextarea.js +0 -17
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.d.ts +0 -32
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.js +0 -85
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyState.d.ts +0 -6
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyState.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyState.js +0 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeader.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeader.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeader.js +0 -5
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts +0 -12
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.js +0 -40
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts +0 -26
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.js +0 -202
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useElementRect.d.ts +0 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useElementRect.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useElementRect.js +0 -46
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts +0 -24
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.js +0 -86
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +0 -34
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +0 -25
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts +0 -37
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.js +0 -52
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/selectorGenerator.d.ts +0 -22
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/selectorGenerator.d.ts.map +0 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/utils/selectorGenerator.js +0 -143
- package/node_modules/@syntrologie/shared-editor-ui/package.json +0 -45
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ElementHighlight — Shared overlay highlight for DOM elements.
|
|
3
|
-
*
|
|
4
|
-
* Tracks element position via useElementRect (scroll/resize-aware).
|
|
5
|
-
* Renders via createPortal to document.body with position: fixed.
|
|
6
|
-
*
|
|
7
|
-
* EXCEPTION: This component MUST stay on document.body (not in shadow root).
|
|
8
|
-
* It tracks and highlights host page elements, and needs same-tree visual
|
|
9
|
-
* stacking context. Uses inline styles exclusively (no CSS leaking concerns).
|
|
10
|
-
*
|
|
11
|
-
* Replaces: InspectHighlight, HighlightOverlay, DiscoveryHighlightOverlay,
|
|
12
|
-
* ReviewHighlightOverlay.
|
|
13
|
-
*/
|
|
14
|
-
import type React from 'react';
|
|
15
|
-
export interface ElementHighlightProps {
|
|
16
|
-
element: HTMLElement;
|
|
17
|
-
color: string;
|
|
18
|
-
bgColor?: string;
|
|
19
|
-
borderStyle?: 'solid' | 'dashed';
|
|
20
|
-
borderWidth?: number;
|
|
21
|
-
label?: string;
|
|
22
|
-
labelIcon?: React.ReactNode;
|
|
23
|
-
showRemove?: boolean;
|
|
24
|
-
onRemove?: () => void;
|
|
25
|
-
onClick?: () => void;
|
|
26
|
-
zIndex?: number;
|
|
27
|
-
padding?: number;
|
|
28
|
-
showDimensions?: boolean;
|
|
29
|
-
className?: string;
|
|
30
|
-
}
|
|
31
|
-
export declare function ElementHighlight({ element, color, bgColor, borderStyle, borderWidth, label, labelIcon, showRemove, onRemove, onClick, zIndex, padding, showDimensions, className, }: ElementHighlightProps): React.ReactPortal | null;
|
|
32
|
-
//# sourceMappingURL=ElementHighlight.d.ts.map
|
package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElementHighlight.d.ts","sourceRoot":"","sources":["../../src/components/ElementHighlight.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,KAAK,EACL,OAAuB,EACvB,WAAqB,EACrB,WAAe,EACf,KAAK,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,OAAO,EACP,MAAmB,EACnB,OAAW,EACX,cAAc,EACd,SAAS,GACV,EAAE,qBAAqB,4BA4HvB"}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createPortal } from 'react-dom';
|
|
3
|
-
import { useElementRect } from '../hooks/useElementRect';
|
|
4
|
-
export function ElementHighlight({ element, color, bgColor = 'transparent', borderStyle = 'solid', borderWidth = 2, label, labelIcon, showRemove, onRemove, onClick, zIndex = 2147483644, padding = 2, showDimensions, className, }) {
|
|
5
|
-
const rect = useElementRect(element);
|
|
6
|
-
if (!rect)
|
|
7
|
-
return null;
|
|
8
|
-
// Build dimensions label from element metadata
|
|
9
|
-
const dimensionsLabel = showDimensions
|
|
10
|
-
? (() => {
|
|
11
|
-
const tag = element.tagName.toLowerCase();
|
|
12
|
-
const id = element.id ? `#${element.id}` : '';
|
|
13
|
-
const cls = element.className && typeof element.className === 'string'
|
|
14
|
-
? `.${element.className.split(' ').filter(Boolean).slice(0, 2).join('.')}`
|
|
15
|
-
: '';
|
|
16
|
-
return `${tag}${id}${cls} \u2014 ${Math.round(rect.width)}\u00d7${Math.round(rect.height)}`;
|
|
17
|
-
})()
|
|
18
|
-
: null;
|
|
19
|
-
const displayLabel = label || dimensionsLabel;
|
|
20
|
-
return createPortal(
|
|
21
|
-
// biome-ignore lint/a11y/noStaticElementInteractions: overlay highlight element is conditionally interactive based on onClick prop
|
|
22
|
-
_jsx("div", { "data-syntro-highlight": true, "data-syntro-editor-ui": "highlight", className: className, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, onClick: onClick
|
|
23
|
-
? (e) => {
|
|
24
|
-
e.stopPropagation();
|
|
25
|
-
e.preventDefault();
|
|
26
|
-
onClick();
|
|
27
|
-
}
|
|
28
|
-
: undefined, onKeyDown: onClick
|
|
29
|
-
? (e) => {
|
|
30
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
31
|
-
e.stopPropagation();
|
|
32
|
-
e.preventDefault();
|
|
33
|
-
onClick();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
: undefined, style: {
|
|
37
|
-
position: 'fixed',
|
|
38
|
-
top: rect.top - padding,
|
|
39
|
-
left: rect.left - padding,
|
|
40
|
-
width: rect.width + padding * 2,
|
|
41
|
-
height: rect.height + padding * 2,
|
|
42
|
-
border: `${borderWidth}px ${borderStyle} ${color}`,
|
|
43
|
-
backgroundColor: bgColor,
|
|
44
|
-
borderRadius: '4px',
|
|
45
|
-
zIndex,
|
|
46
|
-
pointerEvents: onClick || onRemove ? 'auto' : 'none',
|
|
47
|
-
cursor: onClick ? 'pointer' : 'default',
|
|
48
|
-
transition: 'all 0.05s ease-out',
|
|
49
|
-
boxSizing: 'border-box',
|
|
50
|
-
}, children: displayLabel && (_jsxs("div", { "data-syntro-highlight-label": true, "data-syntro-editor-ui": "highlight-label", className: "se-text-xs", style: {
|
|
51
|
-
position: 'absolute',
|
|
52
|
-
top: '-22px',
|
|
53
|
-
left: 0,
|
|
54
|
-
background: showDimensions
|
|
55
|
-
? `${color.replace(')', ',0.85)').replace('rgb(', 'rgba(')}`
|
|
56
|
-
: color,
|
|
57
|
-
color: '#fff',
|
|
58
|
-
fontWeight: 600,
|
|
59
|
-
fontFamily: showDimensions ? 'monospace' : 'inherit',
|
|
60
|
-
padding: '1px 6px',
|
|
61
|
-
borderRadius: '4px',
|
|
62
|
-
whiteSpace: 'nowrap',
|
|
63
|
-
display: 'flex',
|
|
64
|
-
alignItems: 'center',
|
|
65
|
-
gap: '6px',
|
|
66
|
-
pointerEvents: 'auto',
|
|
67
|
-
}, children: [labelIcon, displayLabel, showRemove && onRemove && (_jsx("button", { type: "button", className: "se-text-xs", "data-syntro-highlight-remove": true, "data-syntro-editor-ui": "highlight-remove", onClick: (e) => {
|
|
68
|
-
e.stopPropagation();
|
|
69
|
-
e.preventDefault();
|
|
70
|
-
onRemove();
|
|
71
|
-
}, style: {
|
|
72
|
-
background: 'rgba(0,0,0,0.4)',
|
|
73
|
-
border: 'none',
|
|
74
|
-
color: '#fff',
|
|
75
|
-
borderRadius: '50%',
|
|
76
|
-
width: '16px',
|
|
77
|
-
height: '16px',
|
|
78
|
-
cursor: 'pointer',
|
|
79
|
-
display: 'flex',
|
|
80
|
-
alignItems: 'center',
|
|
81
|
-
justifyContent: 'center',
|
|
82
|
-
padding: 0,
|
|
83
|
-
lineHeight: 1,
|
|
84
|
-
}, children: "\u00D7" }))] })) }), document.body);
|
|
85
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../src/components/EmptyState.tsx"],"names":[],"mappings":"AAAA,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,eAAe,2CAMtD"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface GroupHeaderProps {
|
|
2
|
-
label: string;
|
|
3
|
-
count: number;
|
|
4
|
-
className?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function GroupHeader({ label, count, className }: GroupHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=GroupHeader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GroupHeader.d.ts","sourceRoot":"","sources":["../../src/components/GroupHeader.tsx"],"names":[],"mappings":"AAEA,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CAcxE"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from '../cn';
|
|
3
|
-
export function GroupHeader({ label, count, className }) {
|
|
4
|
-
return (_jsxs("div", { className: cn('se-text-xs se-font-bold se-text-text-primary se-uppercase se-tracking-wide se-py-1 se-pb-2 se-flex se-items-center se-justify-between', className), children: [_jsx("span", { children: label }), _jsx("span", { className: "se-text-xs se-text-text-secondary se-bg-badge-slate-bg se-px-1.5 se-py-0.5 se-rounded-lg", children: count })] }));
|
|
5
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TriggerJourney — compact horizontal node graph for triggerWhen conditions.
|
|
3
|
-
*
|
|
4
|
-
* Displays each condition as a small circle node connected by lines.
|
|
5
|
-
* Nodes light up green as conditions are met.
|
|
6
|
-
*/
|
|
7
|
-
import type { TriggerWhenStatus } from './ConditionStatusLine';
|
|
8
|
-
export interface TriggerJourneyProps {
|
|
9
|
-
status: TriggerWhenStatus | null;
|
|
10
|
-
}
|
|
11
|
-
export declare function TriggerJourney({ status }: TriggerJourneyProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
//# sourceMappingURL=TriggerJourney.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TriggerJourney.d.ts","sourceRoot":"","sources":["../../src/components/TriggerJourney.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAClC;AA4FD,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CA+B7D"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* TriggerJourney — compact horizontal node graph for triggerWhen conditions.
|
|
4
|
-
*
|
|
5
|
-
* Displays each condition as a small circle node connected by lines.
|
|
6
|
-
* Nodes light up green as conditions are met.
|
|
7
|
-
*/
|
|
8
|
-
import { Check } from 'lucide-react';
|
|
9
|
-
import { cn } from '../cn';
|
|
10
|
-
/* ------------------------------------------------------------------ */
|
|
11
|
-
/* Internal: small progress bar for event_count nodes */
|
|
12
|
-
/* ------------------------------------------------------------------ */
|
|
13
|
-
function ProgressBar({ current, target }) {
|
|
14
|
-
const pct = Math.min(100, Math.round((current / Math.max(target, 1)) * 100));
|
|
15
|
-
return (_jsxs("div", { className: "se-flex se-items-center se-gap-0.5", children: [_jsx("span", { className: "se-inline-block se-w-8 se-h-1 se-rounded-full se-bg-white/20", title: `${current}/${target} (${pct}%)`, children: _jsx("span", { className: cn('se-block se-h-full se-rounded-full se-transition-all', pct >= 100 ? 'se-bg-green-4' : 'se-bg-blue-4'), style: { width: `${pct}%` } }) }), _jsxs("span", { className: "se-text-[11px] se-font-medium se-text-text-secondary", children: [current, "/", target] })] }));
|
|
16
|
-
}
|
|
17
|
-
/* ------------------------------------------------------------------ */
|
|
18
|
-
/* Internal: single journey node with label + optional connection */
|
|
19
|
-
/* ------------------------------------------------------------------ */
|
|
20
|
-
function JourneyNode({ cs, isLast }) {
|
|
21
|
-
const hasProgress = !!cs.formatted.progress;
|
|
22
|
-
const inProgress = !cs.passed && hasProgress && cs.formatted.progress.current > 0;
|
|
23
|
-
return (_jsxs("div", { className: "se-flex se-items-center se-gap-0", children: [_jsxs("div", { className: "se-flex se-flex-col se-items-center se-min-w-0", children: [_jsx("div", { "data-journey-node": true, "data-passed": cs.passed ? 'true' : 'false', className: cn('se-w-4 se-h-4 se-rounded-full se-border-2 se-flex se-items-center se-justify-center se-shrink-0', cs.passed
|
|
24
|
-
? 'se-bg-green-4 se-border-green-4'
|
|
25
|
-
: inProgress
|
|
26
|
-
? 'se-bg-blue-4 se-border-blue-4'
|
|
27
|
-
: 'se-bg-transparent se-border-white/30'), children: cs.passed && _jsx(Check, { className: "se-w-2.5 se-h-2.5 se-text-white" }) }), _jsx("span", { className: "se-text-[11px] se-font-medium se-text-text-secondary se-truncate se-max-w-[60px] se-text-center se-mt-0.5", title: cs.formatted.instruction, children: cs.formatted.shortLabel }), hasProgress && (_jsx(ProgressBar, { current: cs.formatted.progress.current, target: cs.formatted.progress.target }))] }), !isLast && (_jsx("div", { "data-journey-line": true, className: cn('se-h-0.5 se-w-4 se-self-start se-mt-2 se-shrink-0', cs.passed ? 'se-bg-green-4' : 'se-bg-white/20') }))] }));
|
|
28
|
-
}
|
|
29
|
-
/* ------------------------------------------------------------------ */
|
|
30
|
-
/* Main component */
|
|
31
|
-
/* ------------------------------------------------------------------ */
|
|
32
|
-
export function TriggerJourney({ status }) {
|
|
33
|
-
if (!status || status.conditions.length === 0) {
|
|
34
|
-
return (_jsx("div", { className: "se-mt-1 se-text-[12px] se-font-medium se-text-text-secondary se-italic", children: "Always Present" }));
|
|
35
|
-
}
|
|
36
|
-
const { conditions } = status;
|
|
37
|
-
const allPassed = conditions.every((c) => c.passed);
|
|
38
|
-
const isMulti = conditions.length > 1;
|
|
39
|
-
return (_jsxs("div", { className: "se-mt-1", children: [_jsx("div", { className: "se-flex se-items-start", children: conditions.map((cs, i) => (_jsx(JourneyNode, { cs: cs, isLast: i === conditions.length - 1 }, i))) }), allPassed && isMulti && (_jsxs("div", { className: "se-flex se-items-center se-gap-1 se-mt-1 se-text-[12px] se-text-green-4", children: [_jsx(Check, { className: "se-w-3 se-h-3" }), _jsx("span", { children: "All conditions met" })] }))] }));
|
|
40
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format a triggerWhen condition into a human-readable label.
|
|
3
|
-
* Pure function — no runtime dependency.
|
|
4
|
-
*/
|
|
5
|
-
interface ConditionLike {
|
|
6
|
-
type: string;
|
|
7
|
-
[key: string]: unknown;
|
|
8
|
-
}
|
|
9
|
-
export interface ConditionProgress {
|
|
10
|
-
current: number;
|
|
11
|
-
target: number;
|
|
12
|
-
operator: string;
|
|
13
|
-
}
|
|
14
|
-
export interface FormattedCondition {
|
|
15
|
-
label: string;
|
|
16
|
-
instruction: string;
|
|
17
|
-
shortLabel: string;
|
|
18
|
-
progress?: ConditionProgress;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Convert a Condition object into a human-readable label.
|
|
22
|
-
* For event_count conditions, also returns progress data.
|
|
23
|
-
*/
|
|
24
|
-
export declare function formatConditionLabel(condition: ConditionLike, accumulatorCount?: number): FormattedCondition;
|
|
25
|
-
export {};
|
|
26
|
-
//# sourceMappingURL=formatConditionLabel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formatConditionLabel.d.ts","sourceRoot":"","sources":["../src/formatConditionLabel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgDD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,aAAa,EACxB,gBAAgB,CAAC,EAAE,MAAM,GACxB,kBAAkB,CAoKpB"}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format a triggerWhen condition into a human-readable label.
|
|
3
|
-
* Pure function — no runtime dependency.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Format match criteria as a parenthetical string.
|
|
7
|
-
* { tagName: 'a' } → '(tagName: a)'
|
|
8
|
-
*/
|
|
9
|
-
function _formatMatch(match) {
|
|
10
|
-
if (!match || Object.keys(match).length === 0)
|
|
11
|
-
return '';
|
|
12
|
-
const parts = Object.entries(match).map(([k, v]) => `${k}: ${v}`);
|
|
13
|
-
return ` (${parts.join(', ')})`;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Format an operator for display.
|
|
17
|
-
*/
|
|
18
|
-
function formatOperator(op) {
|
|
19
|
-
switch (op) {
|
|
20
|
-
case 'gte':
|
|
21
|
-
return '\u2265'; // ≥
|
|
22
|
-
case 'lte':
|
|
23
|
-
return '\u2264'; // ≤
|
|
24
|
-
case 'gt':
|
|
25
|
-
return '>';
|
|
26
|
-
case 'lt':
|
|
27
|
-
return '<';
|
|
28
|
-
case 'eq':
|
|
29
|
-
return '=';
|
|
30
|
-
default:
|
|
31
|
-
return op;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Convert a hyphenated or underscored key into human-readable lowercase text.
|
|
36
|
-
* e.g. "fine-arts-page-views" → "fine arts page views"
|
|
37
|
-
*/
|
|
38
|
-
function humanizeKey(key) {
|
|
39
|
-
return key.replace(/[-_]/g, ' ').toLowerCase();
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Strip trailing wildcard segments from a URL path.
|
|
43
|
-
* e.g. "/fine-arts/**" → "/fine-arts/"
|
|
44
|
-
*/
|
|
45
|
-
function cleanUrl(url) {
|
|
46
|
-
return url.replace(/\/?\*+$/, '/').replace(/\/\/$/, '/');
|
|
47
|
-
}
|
|
48
|
-
// Pre-compiled regexes for event_count classification
|
|
49
|
-
const PAGE_VIEW_RE = /page.?view/i;
|
|
50
|
-
const CLICK_RE = /click/i;
|
|
51
|
-
/**
|
|
52
|
-
* Convert a Condition object into a human-readable label.
|
|
53
|
-
* For event_count conditions, also returns progress data.
|
|
54
|
-
*/
|
|
55
|
-
export function formatConditionLabel(condition, accumulatorCount) {
|
|
56
|
-
switch (condition.type) {
|
|
57
|
-
case 'event_count': {
|
|
58
|
-
const key = condition.key;
|
|
59
|
-
const op = condition.operator;
|
|
60
|
-
const target = condition.count;
|
|
61
|
-
const current = accumulatorCount ?? 0;
|
|
62
|
-
const humanized = humanizeKey(key);
|
|
63
|
-
let instruction;
|
|
64
|
-
let shortLabel;
|
|
65
|
-
if (PAGE_VIEW_RE.test(humanized)) {
|
|
66
|
-
// Extract the topic by removing "page view(s)" from the humanized key
|
|
67
|
-
const topic = humanized.replace(/\s*page\s*views?\s*/i, '').trim();
|
|
68
|
-
instruction = topic
|
|
69
|
-
? `View ${topic} pages ${target}+ times`
|
|
70
|
-
: `View pages ${target}+ times`;
|
|
71
|
-
shortLabel = `View ${target}+ times`;
|
|
72
|
-
}
|
|
73
|
-
else if (CLICK_RE.test(humanized)) {
|
|
74
|
-
const topic = humanized.replace(/\s*clicks?\s*/i, '').trim();
|
|
75
|
-
instruction = topic ? `Click ${topic} ${target}+ times` : `Click ${target}+ times`;
|
|
76
|
-
shortLabel = `${target}+ clicks`;
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
// Generic event
|
|
80
|
-
const lastWord = humanized
|
|
81
|
-
.trim()
|
|
82
|
-
.split(' ')
|
|
83
|
-
.filter((w) => w)
|
|
84
|
-
.pop() || 'events';
|
|
85
|
-
instruction = `Reach ${target}+ ${humanized} events`;
|
|
86
|
-
shortLabel = `${target}+ ${lastWord}s`;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
label: `${key} ${formatOperator(op)} ${target}`,
|
|
90
|
-
instruction,
|
|
91
|
-
shortLabel,
|
|
92
|
-
progress: { current, target, operator: op },
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
case 'page_url': {
|
|
96
|
-
const url = condition.url;
|
|
97
|
-
const cleaned = cleanUrl(url);
|
|
98
|
-
const hasWildcard = url !== cleaned;
|
|
99
|
-
const instruction = hasWildcard ? `Visit a ${cleaned} page` : `Visit ${cleaned}`;
|
|
100
|
-
return {
|
|
101
|
-
label: `${url}`,
|
|
102
|
-
instruction,
|
|
103
|
-
shortLabel: cleaned,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
case 'anchor_visible': {
|
|
107
|
-
const rawAnchor = condition.anchorId;
|
|
108
|
-
const anchorId = typeof rawAnchor === 'string'
|
|
109
|
-
? rawAnchor
|
|
110
|
-
: (rawAnchor?.selector ?? '');
|
|
111
|
-
const state = condition.state;
|
|
112
|
-
return {
|
|
113
|
-
label: `${anchorId} (${state})`,
|
|
114
|
-
instruction: `Scroll until ${anchorId} is ${state}`,
|
|
115
|
-
shortLabel: `${anchorId}`,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
case 'event_occurred': {
|
|
119
|
-
const eventName = condition.eventName;
|
|
120
|
-
return {
|
|
121
|
-
label: `${eventName}`,
|
|
122
|
-
instruction: `Trigger a ${eventName} event`,
|
|
123
|
-
shortLabel: `${eventName}`,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
case 'state_equals': {
|
|
127
|
-
const key = condition.key;
|
|
128
|
-
const val = condition.value === undefined ? 'undefined' : JSON.stringify(condition.value);
|
|
129
|
-
return {
|
|
130
|
-
label: `${key} = ${val}`,
|
|
131
|
-
instruction: `${key} equals ${val}`,
|
|
132
|
-
shortLabel: `${key}`,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
case 'viewport': {
|
|
136
|
-
const parts = [];
|
|
137
|
-
if (condition.minWidth !== undefined)
|
|
138
|
-
parts.push(`w ${formatOperator('gte')} ${condition.minWidth}px`);
|
|
139
|
-
if (condition.maxWidth !== undefined)
|
|
140
|
-
parts.push(`w ${formatOperator('lte')} ${condition.maxWidth}px`);
|
|
141
|
-
if (condition.minHeight !== undefined)
|
|
142
|
-
parts.push(`h ${formatOperator('gte')} ${condition.minHeight}px`);
|
|
143
|
-
if (condition.maxHeight !== undefined)
|
|
144
|
-
parts.push(`h ${formatOperator('lte')} ${condition.maxHeight}px`);
|
|
145
|
-
const label = parts.join(', ') || 'any viewport';
|
|
146
|
-
const instruction = parts.length > 0 ? `Use a viewport ${parts.join(' and ')}` : 'Use a viewport of any size';
|
|
147
|
-
const shortLabel = parts.length > 0 ? parts[0] : 'Any size';
|
|
148
|
-
return { label, instruction, shortLabel };
|
|
149
|
-
}
|
|
150
|
-
case 'session_metric': {
|
|
151
|
-
const key = condition.key;
|
|
152
|
-
const op = condition.operator;
|
|
153
|
-
const threshold = condition.threshold;
|
|
154
|
-
return {
|
|
155
|
-
label: `${key} ${formatOperator(op)} ${threshold}`,
|
|
156
|
-
instruction: `${key} reaches ${threshold}+`,
|
|
157
|
-
shortLabel: `${key} ${threshold}+`,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
case 'dismissed': {
|
|
161
|
-
const inverted = condition.inverted;
|
|
162
|
-
const key = condition.key;
|
|
163
|
-
const target = key || 'this';
|
|
164
|
-
return {
|
|
165
|
-
label: inverted ? 'not dismissed' : 'dismissed',
|
|
166
|
-
instruction: inverted ? `Do not dismiss ${target}` : `Dismiss ${target}`,
|
|
167
|
-
shortLabel: inverted ? 'Not dismissed' : 'Dismissed',
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
case 'cooldown_active': {
|
|
171
|
-
const inverted = condition.inverted;
|
|
172
|
-
return {
|
|
173
|
-
label: inverted ? 'cooldown inactive' : 'cooldown active',
|
|
174
|
-
instruction: inverted ? 'Wait for cooldown to expire' : 'Cooldown is active',
|
|
175
|
-
shortLabel: inverted ? 'Cooldown done' : 'Cooldown active',
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
case 'frequency_limit': {
|
|
179
|
-
const inverted = condition.inverted;
|
|
180
|
-
const limit = condition.limit;
|
|
181
|
-
return {
|
|
182
|
-
label: `shown ${formatOperator(inverted ? 'lt' : 'gte')} ${limit} times`,
|
|
183
|
-
instruction: inverted ? `Shown fewer than ${limit} times` : `Shown ${limit}+ times`,
|
|
184
|
-
shortLabel: inverted ? `< ${limit} views` : `${limit}+ views`,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
case 'route': {
|
|
188
|
-
const routeId = condition.routeId;
|
|
189
|
-
return {
|
|
190
|
-
label: `${routeId}`,
|
|
191
|
-
instruction: `Navigate to ${routeId} route`,
|
|
192
|
-
shortLabel: `${routeId}`,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
default:
|
|
196
|
-
return {
|
|
197
|
-
label: `${condition.type}`,
|
|
198
|
-
instruction: `${condition.type}`,
|
|
199
|
-
shortLabel: `${condition.type}`,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns a live DOMRect for an element, updating on scroll, resize,
|
|
3
|
-
* and element size changes.
|
|
4
|
-
*
|
|
5
|
-
* Uses requestAnimationFrame to batch updates and avoid layout thrashing.
|
|
6
|
-
*/
|
|
7
|
-
export declare function useElementRect(element: HTMLElement | null): DOMRect | null;
|
|
8
|
-
//# sourceMappingURL=useElementRect.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useElementRect.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementRect.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CA6C1E"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Returns a live DOMRect for an element, updating on scroll, resize,
|
|
4
|
-
* and element size changes.
|
|
5
|
-
*
|
|
6
|
-
* Uses requestAnimationFrame to batch updates and avoid layout thrashing.
|
|
7
|
-
*/
|
|
8
|
-
export function useElementRect(element) {
|
|
9
|
-
const [rect, setRect] = useState(null);
|
|
10
|
-
const update = useCallback(() => {
|
|
11
|
-
if (element) {
|
|
12
|
-
setRect(element.getBoundingClientRect());
|
|
13
|
-
}
|
|
14
|
-
}, [element]);
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (!element) {
|
|
17
|
-
setRect(null);
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
// Initial measurement
|
|
21
|
-
setRect(element.getBoundingClientRect());
|
|
22
|
-
let rafId = null;
|
|
23
|
-
const scheduleUpdate = () => {
|
|
24
|
-
if (rafId != null)
|
|
25
|
-
return;
|
|
26
|
-
rafId = requestAnimationFrame(() => {
|
|
27
|
-
rafId = null;
|
|
28
|
-
update();
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
// Scroll (capture phase catches nested scroll containers)
|
|
32
|
-
window.addEventListener('scroll', scheduleUpdate, true);
|
|
33
|
-
window.addEventListener('resize', scheduleUpdate);
|
|
34
|
-
// Observe element size changes
|
|
35
|
-
const ro = new ResizeObserver(scheduleUpdate);
|
|
36
|
-
ro.observe(element);
|
|
37
|
-
return () => {
|
|
38
|
-
window.removeEventListener('scroll', scheduleUpdate, true);
|
|
39
|
-
window.removeEventListener('resize', scheduleUpdate);
|
|
40
|
-
ro.disconnect();
|
|
41
|
-
if (rafId != null)
|
|
42
|
-
cancelAnimationFrame(rafId);
|
|
43
|
-
};
|
|
44
|
-
}, [element, update]);
|
|
45
|
-
return rect;
|
|
46
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { TriggerWhenStatus } from '../components/ConditionStatusLine';
|
|
2
|
-
/**
|
|
3
|
-
* Minimal type for a triggerWhen action item.
|
|
4
|
-
* Works with both FAQQuestionAction and NavTipAction.
|
|
5
|
-
*/
|
|
6
|
-
export interface TriggerWhenItem {
|
|
7
|
-
id: string;
|
|
8
|
-
triggerWhen?: {
|
|
9
|
-
type: string;
|
|
10
|
-
rules?: Array<{
|
|
11
|
-
conditions: Array<Record<string, unknown>>;
|
|
12
|
-
value: unknown;
|
|
13
|
-
}>;
|
|
14
|
-
default?: unknown;
|
|
15
|
-
} | null;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Hook: live triggerWhen evaluation for a list of action items.
|
|
19
|
-
*
|
|
20
|
-
* @param items Array of items with id + optional triggerWhen
|
|
21
|
-
* @returns Map from item id → TriggerWhenStatus (null for items without triggerWhen)
|
|
22
|
-
*/
|
|
23
|
-
export declare function useTriggerWhenStatus(items: TriggerWhenItem[]): Map<string, TriggerWhenStatus | null>;
|
|
24
|
-
//# sourceMappingURL=useTriggerWhenStatus.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTriggerWhenStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useTriggerWhenStatus.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAG5F;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,KAAK,CAAC;YACZ,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YAC3C,KAAK,EAAE,OAAO,CAAC;SAChB,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,IAAI,CAAC;CACV;AAqED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,EAAE,GACvB,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,CA0CvC"}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useTriggerWhenStatus — live triggerWhen evaluation for editor diagnostics.
|
|
3
|
-
*
|
|
4
|
-
* Delegates condition evaluation to the runtime's evaluateSync() method,
|
|
5
|
-
* eliminating duplicated logic. Subscribes to the EventAccumulator for
|
|
6
|
-
* reactive updates.
|
|
7
|
-
*
|
|
8
|
-
* NOTE: This hook accesses `window.SynOS.handle.runtime` directly
|
|
9
|
-
* because EditorPanelProps doesn't expose runtime. This is safe —
|
|
10
|
-
* the editor only runs after runtime bootstrap.
|
|
11
|
-
*/
|
|
12
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
13
|
-
import { formatConditionLabel } from '../formatConditionLabel';
|
|
14
|
-
/**
|
|
15
|
-
* Build a RuntimeLike from the real SynOS.handle.runtime.
|
|
16
|
-
*/
|
|
17
|
-
function getRuntime() {
|
|
18
|
-
const rt = window.SynOS?.handle?.runtime;
|
|
19
|
-
if (!rt?.evaluateSync)
|
|
20
|
-
return null;
|
|
21
|
-
return {
|
|
22
|
-
evaluateSync: rt.evaluateSync.bind(rt),
|
|
23
|
-
accumulator: rt.accumulator,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Evaluate all conditions in a triggerWhen RuleStrategy via the runtime engine.
|
|
28
|
-
*/
|
|
29
|
-
function evaluateTriggerWhen(triggerWhen, runtime) {
|
|
30
|
-
if (triggerWhen.type !== 'rules' || !triggerWhen.rules?.length) {
|
|
31
|
-
return { visible: !!triggerWhen.default, isFallback: true, conditions: [] };
|
|
32
|
-
}
|
|
33
|
-
const result = runtime.evaluateSync(triggerWhen);
|
|
34
|
-
const conditions = (result.matchInfo?.evaluatedConditions ?? []).map(({ condition, result: passed }) => {
|
|
35
|
-
// Get live accumulator count for event_count progress display
|
|
36
|
-
const accCount = condition.type === 'event_count' && runtime.accumulator
|
|
37
|
-
? runtime.accumulator.getCount(condition.key, condition.withinMs)
|
|
38
|
-
: undefined;
|
|
39
|
-
const formatted = formatConditionLabel(condition, accCount);
|
|
40
|
-
return { type: condition.type, passed, formatted };
|
|
41
|
-
});
|
|
42
|
-
return { visible: result.value, isFallback: result.isFallback, conditions };
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Hook: live triggerWhen evaluation for a list of action items.
|
|
46
|
-
*
|
|
47
|
-
* @param items Array of items with id + optional triggerWhen
|
|
48
|
-
* @returns Map from item id → TriggerWhenStatus (null for items without triggerWhen)
|
|
49
|
-
*/
|
|
50
|
-
export function useTriggerWhenStatus(items) {
|
|
51
|
-
const [statuses, setStatuses] = useState(new Map());
|
|
52
|
-
const itemsRef = useRef(items);
|
|
53
|
-
itemsRef.current = items;
|
|
54
|
-
const evaluate = useCallback(() => {
|
|
55
|
-
const runtime = getRuntime();
|
|
56
|
-
if (!runtime)
|
|
57
|
-
return;
|
|
58
|
-
const map = new Map();
|
|
59
|
-
for (const item of itemsRef.current) {
|
|
60
|
-
if (!item.triggerWhen) {
|
|
61
|
-
map.set(item.id, null);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
map.set(item.id, evaluateTriggerWhen(item.triggerWhen, runtime));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
setStatuses(map);
|
|
68
|
-
}, []);
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
// Initial evaluation
|
|
71
|
-
evaluate();
|
|
72
|
-
// Subscribe to accumulator changes for reactive event_count updates
|
|
73
|
-
const runtime = getRuntime();
|
|
74
|
-
const unsubs = [];
|
|
75
|
-
if (runtime?.accumulator) {
|
|
76
|
-
unsubs.push(runtime.accumulator.subscribe(evaluate));
|
|
77
|
-
}
|
|
78
|
-
// Poll every 2s for non-accumulator conditions (page_url, viewport, etc.)
|
|
79
|
-
const interval = setInterval(evaluate, 2000);
|
|
80
|
-
return () => {
|
|
81
|
-
unsubs.forEach((u) => u());
|
|
82
|
-
clearInterval(interval);
|
|
83
|
-
};
|
|
84
|
-
}, [evaluate]);
|
|
85
|
-
return statuses;
|
|
86
|
-
}
|