@syntrologie/adapt-content 2.5.1 → 2.6.0-canary.2

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 (76) hide show
  1. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +1 -1
  2. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.js +22 -153
  3. package/node_modules/@syntrologie/shared-editor-ui/package.json +2 -2
  4. package/package.json +1 -1
  5. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts +0 -2
  6. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts.map +0 -1
  7. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.js +0 -224
  8. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/BeforeAfterToggle.test.d.ts +0 -2
  9. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/BeforeAfterToggle.test.d.ts.map +0 -1
  10. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/BeforeAfterToggle.test.js +0 -29
  11. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.d.ts +0 -2
  12. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.d.ts.map +0 -1
  13. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.js +0 -260
  14. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.d.ts +0 -2
  15. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.d.ts.map +0 -1
  16. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.js +0 -70
  17. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.d.ts +0 -2
  18. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.d.ts.map +0 -1
  19. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.js +0 -46
  20. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditBackButton.test.d.ts +0 -2
  21. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditBackButton.test.d.ts.map +0 -1
  22. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditBackButton.test.js +0 -20
  23. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorBody.test.d.ts +0 -2
  24. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorBody.test.d.ts.map +0 -1
  25. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorBody.test.js +0 -12
  26. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.d.ts +0 -2
  27. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.d.ts.map +0 -1
  28. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.js +0 -84
  29. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorFooter.test.d.ts +0 -2
  30. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorFooter.test.d.ts.map +0 -1
  31. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorFooter.test.js +0 -23
  32. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorHeader.test.d.ts +0 -2
  33. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorHeader.test.d.ts.map +0 -1
  34. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorHeader.test.js +0 -23
  35. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorInput.test.d.ts +0 -2
  36. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorInput.test.d.ts.map +0 -1
  37. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorInput.test.js +0 -26
  38. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorLayout.test.d.ts +0 -2
  39. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorLayout.test.d.ts.map +0 -1
  40. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorLayout.test.js +0 -13
  41. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.d.ts +0 -2
  42. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.d.ts.map +0 -1
  43. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.js +0 -496
  44. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorSelect.test.d.ts +0 -2
  45. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorSelect.test.d.ts.map +0 -1
  46. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorSelect.test.js +0 -22
  47. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorTextarea.test.d.ts +0 -2
  48. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorTextarea.test.d.ts.map +0 -1
  49. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorTextarea.test.js +0 -20
  50. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.d.ts +0 -2
  51. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.d.ts.map +0 -1
  52. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.js +0 -176
  53. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EmptyState.test.d.ts +0 -2
  54. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EmptyState.test.d.ts.map +0 -1
  55. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EmptyState.test.js +0 -10
  56. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/GroupHeader.test.d.ts +0 -2
  57. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/GroupHeader.test.d.ts.map +0 -1
  58. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/GroupHeader.test.js +0 -14
  59. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/TriggerJourney.test.d.ts +0 -2
  60. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/TriggerJourney.test.d.ts.map +0 -1
  61. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/TriggerJourney.test.js +0 -189
  62. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/cn.test.d.ts +0 -2
  63. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/cn.test.d.ts.map +0 -1
  64. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/cn.test.js +0 -16
  65. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/formatConditionLabel.test.d.ts +0 -2
  66. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/formatConditionLabel.test.d.ts.map +0 -1
  67. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/formatConditionLabel.test.js +0 -329
  68. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts +0 -2
  69. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts.map +0 -1
  70. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.js +0 -257
  71. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useElementRect.test.d.ts +0 -2
  72. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useElementRect.test.d.ts.map +0 -1
  73. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useElementRect.test.js +0 -112
  74. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts +0 -2
  75. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts.map +0 -1
  76. package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.js +0 -1015
@@ -1 +1 @@
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;AA2ND;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,EAAE,GACvB,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,CA0CvC"}
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;AAsED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,EAAE,GACvB,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC,CA0CvC"}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * useTriggerWhenStatus — live triggerWhen evaluation for editor diagnostics.
3
3
  *
4
- * Subscribes to the runtime's EventAccumulator for reactive updates.
5
- * Evaluates each item's triggerWhen strategy locally to get
6
- * per-condition breakdowns.
4
+ * Delegates condition evaluation to the runtime's evaluateSync() method,
5
+ * eliminating duplicated logic. Subscribes to the EventAccumulator for
6
+ * reactive updates.
7
7
  *
8
8
  * NOTE: This hook accesses `window.SynOS.handle.runtime` directly
9
9
  * because EditorPanelProps doesn't expose runtime. This is safe —
@@ -11,167 +11,36 @@
11
11
  */
12
12
  import { useCallback, useEffect, useRef, useState } from 'react';
13
13
  import { formatConditionLabel } from '../formatConditionLabel';
14
- function getRuntime() {
15
- return window.SynOS?.handle?.runtime ?? null;
16
- }
17
14
  /**
18
- * Evaluate a single condition against the runtime context.
15
+ * Build a RuntimeLike from the real SynOS.handle.runtime.
19
16
  */
20
- function evaluateConditionLocally(condition, runtime) {
21
- const ctx = runtime.context.get();
22
- const type = condition.type;
23
- let passed = false;
24
- let accCount;
25
- switch (type) {
26
- case 'event_count': {
27
- if (!runtime.accumulator)
28
- break;
29
- const key = condition.key;
30
- const withinMs = condition.withinMs;
31
- const count = runtime.accumulator.getCount(key, withinMs);
32
- accCount = count;
33
- const target = condition.count;
34
- const op = condition.operator;
35
- switch (op) {
36
- case 'gte':
37
- passed = count >= target;
38
- break;
39
- case 'lte':
40
- passed = count <= target;
41
- break;
42
- case 'eq':
43
- passed = count === target;
44
- break;
45
- case 'gt':
46
- passed = count > target;
47
- break;
48
- case 'lt':
49
- passed = count < target;
50
- break;
51
- }
52
- break;
53
- }
54
- case 'page_url': {
55
- const url = condition.url;
56
- const pattern = url
57
- .replace(/[.+^${}()|[\]\\]/g, '\\$&')
58
- .replace(/\*\*/g, '.*')
59
- .replace(/\*/g, '[^/]*');
60
- passed = new RegExp(`^${pattern}$`).test(ctx.page.url);
61
- break;
62
- }
63
- case 'route':
64
- passed = ctx.page.routeId === condition.routeId;
65
- break;
66
- case 'anchor_visible': {
67
- const anchors = ctx.anchors;
68
- const condSelector = typeof condition.anchorId === 'string'
69
- ? condition.anchorId
70
- : (condition.anchorId?.selector ?? '');
71
- const anchor = anchors?.find((a) => a.anchorId === condSelector);
72
- switch (condition.state) {
73
- case 'visible':
74
- passed = anchor?.visible === true;
75
- break;
76
- case 'present':
77
- passed = anchor?.present === true;
78
- break;
79
- case 'absent':
80
- passed = !anchor?.present;
81
- break;
82
- }
83
- break;
84
- }
85
- case 'event_occurred':
86
- passed =
87
- runtime.events?.hasRecentEvent(condition.eventName, condition.withinMs ?? 60000) ?? false;
88
- break;
89
- case 'viewport': {
90
- const { width, height } = ctx.viewport;
91
- passed = true;
92
- if (condition.minWidth !== undefined && width < condition.minWidth)
93
- passed = false;
94
- if (condition.maxWidth !== undefined && width > condition.maxWidth)
95
- passed = false;
96
- if (condition.minHeight !== undefined && height < condition.minHeight)
97
- passed = false;
98
- if (condition.maxHeight !== undefined && height > condition.maxHeight)
99
- passed = false;
100
- break;
101
- }
102
- case 'session_metric': {
103
- const val = runtime.state?.getSessionMetric(condition.key) ?? 0;
104
- const threshold = condition.threshold;
105
- const op = condition.operator;
106
- switch (op) {
107
- case 'gte':
108
- passed = val >= threshold;
109
- break;
110
- case 'lte':
111
- passed = val <= threshold;
112
- break;
113
- case 'eq':
114
- passed = val === threshold;
115
- break;
116
- case 'gt':
117
- passed = val > threshold;
118
- break;
119
- case 'lt':
120
- passed = val < threshold;
121
- break;
122
- }
123
- break;
124
- }
125
- case 'dismissed':
126
- passed = condition.inverted
127
- ? !(runtime.state?.isDismissed(condition.key) ?? false)
128
- : (runtime.state?.isDismissed(condition.key) ?? false);
129
- break;
130
- case 'cooldown_active':
131
- passed = condition.inverted
132
- ? !(runtime.state?.isCooldownActive(condition.key) ?? false)
133
- : (runtime.state?.isCooldownActive(condition.key) ?? false);
134
- break;
135
- case 'frequency_limit': {
136
- const count = runtime.state?.getFrequencyCount(condition.key) ?? 0;
137
- const limitReached = count >= condition.limit;
138
- passed = condition.inverted ? !limitReached : limitReached;
139
- break;
140
- }
141
- }
142
- const formatted = formatConditionLabel(condition, accCount);
17
+ function getRuntime() {
18
+ // biome-ignore lint: window.SynOS is set by the runtime SDK
19
+ const rt = window.SynOS?.handle?.runtime;
20
+ if (!rt?.evaluateSync)
21
+ return null;
143
22
  return {
144
- passed,
145
- cs: { type, passed, formatted },
23
+ evaluateSync: rt.evaluateSync.bind(rt),
24
+ accumulator: rt.accumulator,
146
25
  };
147
26
  }
148
27
  /**
149
- * Evaluate all conditions in a triggerWhen RuleStrategy.
28
+ * Evaluate all conditions in a triggerWhen RuleStrategy via the runtime engine.
150
29
  */
151
30
  function evaluateTriggerWhen(triggerWhen, runtime) {
152
31
  if (triggerWhen.type !== 'rules' || !triggerWhen.rules?.length) {
153
32
  return { visible: !!triggerWhen.default, isFallback: true, conditions: [] };
154
33
  }
155
- // Evaluate ALL rules' conditions for diagnostic display
156
- const allConditions = [];
157
- for (const rule of triggerWhen.rules) {
158
- let ruleMatched = true;
159
- for (const condition of rule.conditions) {
160
- const { passed, cs } = evaluateConditionLocally(condition, runtime);
161
- allConditions.push(cs);
162
- if (!passed)
163
- ruleMatched = false;
164
- }
165
- if (ruleMatched) {
166
- return { visible: rule.value, isFallback: false, conditions: allConditions };
167
- }
168
- }
169
- // No rules matched — use default
170
- return {
171
- visible: triggerWhen.default ?? false,
172
- isFallback: true,
173
- conditions: allConditions,
174
- };
34
+ const result = runtime.evaluateSync(triggerWhen);
35
+ const conditions = (result.matchInfo?.evaluatedConditions ?? []).map(({ condition, result: passed }) => {
36
+ // Get live accumulator count for event_count progress display
37
+ const accCount = condition.type === 'event_count' && runtime.accumulator
38
+ ? runtime.accumulator.getCount(condition.key, condition.withinMs)
39
+ : undefined;
40
+ const formatted = formatConditionLabel(condition, accCount);
41
+ return { type: condition.type, passed, formatted };
42
+ });
43
+ return { visible: result.value, isFallback: result.isFallback, conditions };
175
44
  }
176
45
  /**
177
46
  * Hook: live triggerWhen evaluation for a list of action items.
@@ -28,9 +28,9 @@
28
28
  "css-selector-generator": "^3.8.0"
29
29
  },
30
30
  "peerDependencies": {
31
+ "lucide-react": ">=0.400.0",
31
32
  "react": ">=18.0.0",
32
- "react-dom": ">=18.0.0",
33
- "lucide-react": ">=0.400.0"
33
+ "react-dom": ">=18.0.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@testing-library/dom": "^10.4.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/adapt-content",
3
- "version": "2.5.1",
3
+ "version": "2.6.0-canary.2",
4
4
  "description": "Adaptive Content app - DOM manipulation actions for text, attributes, and styles",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=AnchorPicker.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AnchorPicker.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/AnchorPicker.test.tsx"],"names":[],"mappings":""}
@@ -1,224 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { act, render } from '@testing-library/react';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { AnchorPicker } from '../components/AnchorPicker';
5
- // Mock ResizeObserver for jsdom
6
- vi.stubGlobal('ResizeObserver', class {
7
- observe() { }
8
- unobserve() { }
9
- disconnect() { }
10
- });
11
- // Mock selectorGenerator utilities
12
- vi.mock('../utils/selectorGenerator', () => ({
13
- generateSelector: vi.fn((el) => `mock-selector-${el.tagName.toLowerCase()}`),
14
- validateSelector: vi.fn(() => true),
15
- getElementDescription: vi.fn((el) => `mock-desc-${el.tagName.toLowerCase()}`),
16
- }));
17
- import { generateSelector, getElementDescription, validateSelector, } from '../utils/selectorGenerator';
18
- describe('AnchorPicker', () => {
19
- let mockElementAtPoint;
20
- beforeEach(() => {
21
- mockElementAtPoint = document.createElement('div');
22
- mockElementAtPoint.textContent = 'Target Element';
23
- document.body.appendChild(mockElementAtPoint);
24
- vi.spyOn(mockElementAtPoint, 'getBoundingClientRect').mockReturnValue({
25
- top: 100,
26
- left: 200,
27
- width: 300,
28
- height: 150,
29
- bottom: 250,
30
- right: 500,
31
- x: 200,
32
- y: 100,
33
- toJSON: () => ({}),
34
- });
35
- vi.mocked(generateSelector).mockClear();
36
- vi.mocked(validateSelector).mockClear();
37
- vi.mocked(getElementDescription).mockClear();
38
- vi.mocked(generateSelector).mockImplementation((el) => `mock-selector-${el.tagName.toLowerCase()}`);
39
- vi.mocked(validateSelector).mockReturnValue(true);
40
- vi.mocked(getElementDescription).mockImplementation((el) => `mock-desc-${el.tagName.toLowerCase()}`);
41
- // Stub elementFromPoint on document (jsdom does not define it)
42
- if (!document.elementFromPoint) {
43
- document.elementFromPoint = vi.fn(() => null);
44
- }
45
- else {
46
- vi.spyOn(document, 'elementFromPoint').mockReturnValue(null);
47
- }
48
- });
49
- afterEach(() => {
50
- if (mockElementAtPoint.parentNode) {
51
- mockElementAtPoint.remove();
52
- }
53
- vi.restoreAllMocks();
54
- });
55
- it('renders nothing when isActive is false', () => {
56
- render(_jsx(AnchorPicker, { isActive: false, onPick: vi.fn(), onCancel: vi.fn() }));
57
- const picker = document.body.querySelector('[data-syntro-anchor-picker]');
58
- expect(picker).toBeNull();
59
- });
60
- it('renders overlay portal to document.body when active', () => {
61
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
62
- const picker = document.body.querySelector('[data-syntro-anchor-picker]');
63
- expect(picker).toBeTruthy();
64
- unmount();
65
- });
66
- it('sets crosshair cursor on overlay', () => {
67
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
68
- const picker = document.body.querySelector('[data-syntro-anchor-picker]');
69
- expect(picker.style.cursor).toBe('crosshair');
70
- unmount();
71
- });
72
- it('sets highest z-index on overlay', () => {
73
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
74
- const picker = document.body.querySelector('[data-syntro-anchor-picker]');
75
- expect(picker.style.zIndex).toBe('2147483644');
76
- unmount();
77
- });
78
- it('calls onCancel when Escape key is pressed', () => {
79
- const onCancel = vi.fn();
80
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: onCancel }));
81
- act(() => {
82
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
83
- });
84
- expect(onCancel).toHaveBeenCalledTimes(1);
85
- unmount();
86
- });
87
- it('does not call onCancel for non-Escape keys', () => {
88
- const onCancel = vi.fn();
89
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: onCancel }));
90
- act(() => {
91
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
92
- });
93
- expect(onCancel).not.toHaveBeenCalled();
94
- unmount();
95
- });
96
- it('highlights element on mousemove via elementFromPoint', () => {
97
- document.elementFromPoint.mockReturnValue(mockElementAtPoint);
98
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
99
- act(() => {
100
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 250, clientY: 150, bubbles: true }));
101
- });
102
- // generateSelector should have been called with the element
103
- expect(generateSelector).toHaveBeenCalledWith(mockElementAtPoint);
104
- unmount();
105
- });
106
- it('clears hover state when elementFromPoint returns null', () => {
107
- document.elementFromPoint.mockReturnValue(null);
108
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
109
- act(() => {
110
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 250, clientY: 150, bubbles: true }));
111
- });
112
- // No highlight should be shown (just the overlay container + the semi-transparent bg div)
113
- const picker = document.body.querySelector('[data-syntro-anchor-picker]');
114
- expect(picker.children.length).toBe(1);
115
- unmount();
116
- });
117
- it('excludes editor panel elements from picking', () => {
118
- const editorPanel = document.createElement('div');
119
- editorPanel.setAttribute('data-syntro-editor-panel', '');
120
- const innerEl = document.createElement('span');
121
- editorPanel.appendChild(innerEl);
122
- document.body.appendChild(editorPanel);
123
- document.elementFromPoint.mockReturnValue(innerEl);
124
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
125
- act(() => {
126
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 100, clientY: 100, bubbles: true }));
127
- });
128
- // Should not call generateSelector for excluded elements
129
- expect(generateSelector).not.toHaveBeenCalled();
130
- editorPanel.remove();
131
- unmount();
132
- });
133
- it('excludes HTML, BODY, HEAD elements from picking', () => {
134
- document.elementFromPoint.mockReturnValue(document.body);
135
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
136
- act(() => {
137
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 100, clientY: 100, bubbles: true }));
138
- });
139
- expect(generateSelector).not.toHaveBeenCalled();
140
- unmount();
141
- });
142
- it('calls onPick with valid selector on click after hover', () => {
143
- const onPick = vi.fn();
144
- document.elementFromPoint.mockReturnValue(mockElementAtPoint);
145
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: onPick, onCancel: vi.fn() }));
146
- // First hover to set the hovered element
147
- act(() => {
148
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 250, clientY: 150, bubbles: true }));
149
- });
150
- // Then click
151
- act(() => {
152
- document.dispatchEvent(new MouseEvent('click', { clientX: 250, clientY: 150, bubbles: true }));
153
- });
154
- expect(onPick).toHaveBeenCalledTimes(1);
155
- expect(onPick).toHaveBeenCalledWith({
156
- element: mockElementAtPoint,
157
- selector: 'mock-selector-div',
158
- description: 'mock-desc-div',
159
- });
160
- unmount();
161
- });
162
- it('regenerates selector when validation fails on click', () => {
163
- const onPick = vi.fn();
164
- document.elementFromPoint.mockReturnValue(mockElementAtPoint);
165
- vi.mocked(validateSelector).mockReturnValue(false);
166
- vi.mocked(generateSelector).mockReturnValue('regenerated-selector');
167
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: onPick, onCancel: vi.fn() }));
168
- // Hover to set element
169
- act(() => {
170
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 250, clientY: 150, bubbles: true }));
171
- });
172
- // Click
173
- act(() => {
174
- document.dispatchEvent(new MouseEvent('click', { clientX: 250, clientY: 150, bubbles: true }));
175
- });
176
- expect(onPick).toHaveBeenCalledWith(expect.objectContaining({
177
- selector: 'regenerated-selector',
178
- }));
179
- unmount();
180
- });
181
- it('does not call onPick when no element is hovered on click', () => {
182
- const onPick = vi.fn();
183
- document.elementFromPoint.mockReturnValue(null);
184
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: onPick, onCancel: vi.fn() }));
185
- act(() => {
186
- document.dispatchEvent(new MouseEvent('click', { clientX: 250, clientY: 150, bubbles: true }));
187
- });
188
- expect(onPick).not.toHaveBeenCalled();
189
- unmount();
190
- });
191
- it('removes event listeners when deactivated', () => {
192
- const onCancel = vi.fn();
193
- const { rerender, unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: onCancel }));
194
- // Deactivate
195
- rerender(_jsx(AnchorPicker, { isActive: false, onPick: vi.fn(), onCancel: onCancel }));
196
- // Escape should not trigger onCancel after deactivation
197
- act(() => {
198
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
199
- });
200
- expect(onCancel).not.toHaveBeenCalled();
201
- unmount();
202
- });
203
- it('temporarily disables pointer events on overlay during mousemove detection', () => {
204
- const overlayPointerEvents = [];
205
- document.elementFromPoint.mockImplementation(() => {
206
- // Capture overlay pointer events state during elementFromPoint call
207
- const overlay = document.body.querySelector('[data-syntro-anchor-picker]');
208
- if (overlay) {
209
- overlayPointerEvents.push(overlay.style.pointerEvents);
210
- }
211
- return mockElementAtPoint;
212
- });
213
- const { unmount } = render(_jsx(AnchorPicker, { isActive: true, onPick: vi.fn(), onCancel: vi.fn() }));
214
- act(() => {
215
- document.dispatchEvent(new MouseEvent('mousemove', { clientX: 250, clientY: 150, bubbles: true }));
216
- });
217
- // During elementFromPoint, overlay pointerEvents should be 'none'
218
- expect(overlayPointerEvents).toContain('none');
219
- // After the call, it should be restored to 'auto'
220
- const overlay = document.body.querySelector('[data-syntro-anchor-picker]');
221
- expect(overlay.style.pointerEvents).toBe('auto');
222
- unmount();
223
- });
224
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BeforeAfterToggle.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BeforeAfterToggle.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/BeforeAfterToggle.test.tsx"],"names":[],"mappings":""}
@@ -1,29 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { fireEvent, render } from '@testing-library/react';
3
- import { describe, expect, it, vi } from 'vitest';
4
- import { BeforeAfterToggle } from '../components/BeforeAfterToggle';
5
- describe('BeforeAfterToggle', () => {
6
- it('renders Before and After buttons', () => {
7
- const { getByText } = render(_jsx(BeforeAfterToggle, { mode: "before", onToggle: () => { } }));
8
- expect(getByText('Before')).toBeTruthy();
9
- expect(getByText('After')).toBeTruthy();
10
- });
11
- it('calls onToggle with "before" when Before is clicked', () => {
12
- const onToggle = vi.fn();
13
- const { getByText } = render(_jsx(BeforeAfterToggle, { mode: "after", onToggle: onToggle }));
14
- fireEvent.click(getByText('Before'));
15
- expect(onToggle).toHaveBeenCalledWith('before');
16
- });
17
- it('calls onToggle with "after" when After is clicked', () => {
18
- const onToggle = vi.fn();
19
- const { getByText } = render(_jsx(BeforeAfterToggle, { mode: "before", onToggle: onToggle }));
20
- fireEvent.click(getByText('After'));
21
- expect(onToggle).toHaveBeenCalledWith('after');
22
- });
23
- it('highlights active mode with blue class', () => {
24
- const { getByText } = render(_jsx(BeforeAfterToggle, { mode: "before", onToggle: () => { } }));
25
- expect(getByText('Before').className).toContain('se-text-blue-5');
26
- expect(getByText('Before').className).toContain('se-bg-blue-5/30');
27
- expect(getByText('After').className).toContain('se-text-text-secondary');
28
- });
29
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ConditionStatusLine.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ConditionStatusLine.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ConditionStatusLine.test.tsx"],"names":[],"mappings":""}