@salesforce/webapp-experimental 1.47.0 → 1.48.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 (35) hide show
  1. package/dist/design/design-mode-interactions.js +649 -0
  2. package/dist/design/index.d.ts +12 -0
  3. package/dist/design/index.d.ts.map +1 -0
  4. package/dist/design/index.js +21 -0
  5. package/dist/design/interactions/communicationManager.d.ts +25 -0
  6. package/dist/design/interactions/communicationManager.d.ts.map +1 -0
  7. package/dist/design/interactions/communicationManager.js +112 -0
  8. package/dist/design/interactions/componentMatcher.d.ts +37 -0
  9. package/dist/design/interactions/componentMatcher.d.ts.map +1 -0
  10. package/dist/design/interactions/componentMatcher.js +68 -0
  11. package/dist/design/interactions/editableManager.d.ts +51 -0
  12. package/dist/design/interactions/editableManager.d.ts.map +1 -0
  13. package/dist/design/interactions/editableManager.js +90 -0
  14. package/dist/design/interactions/eventHandlers.d.ts +66 -0
  15. package/dist/design/interactions/eventHandlers.d.ts.map +1 -0
  16. package/dist/design/interactions/eventHandlers.js +136 -0
  17. package/dist/design/interactions/index.d.ts +7 -0
  18. package/dist/design/interactions/index.d.ts.map +1 -0
  19. package/dist/design/interactions/index.js +45 -0
  20. package/dist/design/interactions/interactionsController.d.ts +38 -0
  21. package/dist/design/interactions/interactionsController.d.ts.map +1 -0
  22. package/dist/design/interactions/interactionsController.js +86 -0
  23. package/dist/design/interactions/styleManager.d.ts +49 -0
  24. package/dist/design/interactions/styleManager.d.ts.map +1 -0
  25. package/dist/design/interactions/styleManager.js +89 -0
  26. package/dist/design/interactions/utils/cssUtils.d.ts +22 -0
  27. package/dist/design/interactions/utils/cssUtils.d.ts.map +1 -0
  28. package/dist/design/interactions/utils/cssUtils.js +46 -0
  29. package/dist/design/interactions/utils/sourceUtils.d.ts +23 -0
  30. package/dist/design/interactions/utils/sourceUtils.d.ts.map +1 -0
  31. package/dist/design/interactions/utils/sourceUtils.js +64 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +1 -0
  35. package/package.json +10 -4
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ export declare class CommunicationManager {
7
+ constructor();
8
+ /**
9
+ * Notify the extension about a selected component
10
+ * @param element - The selected element
11
+ */
12
+ notifyComponentSelected(element: HTMLElement): void;
13
+ /**
14
+ * Notify the extension about a text change
15
+ * @param element - The element that changed
16
+ * @param originalText - The original text
17
+ * @param newText - The new text
18
+ */
19
+ notifyTextChange(element: HTMLElement, originalText: string, newText: string): void;
20
+ /**
21
+ * Notify the parent window that interactions initialization is complete
22
+ */
23
+ notifyInitializationComplete(): void;
24
+ }
25
+ //# sourceMappingURL=communicationManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"communicationManager.d.ts","sourceRoot":"","sources":["../../../src/design/interactions/communicationManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,qBAAa,oBAAoB;;IAKhC;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAwDnD;;;;;OAKG;IACH,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA2BnF;;OAEG;IACH,4BAA4B,IAAI,IAAI;CAepC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Communication Manager Module
8
+ * Handles communication with the parent window (VS Code extension)
9
+ */
10
+ import { getElementStyles } from "./utils/cssUtils.js";
11
+ import { getLabelFromSource, getSourceFromDataAttributes } from "./utils/sourceUtils.js";
12
+ export class CommunicationManager {
13
+ constructor() {
14
+ // CommunicationManager has no required initialization
15
+ }
16
+ /**
17
+ * Notify the extension about a selected component
18
+ * @param element - The selected element
19
+ */
20
+ notifyComponentSelected(element) {
21
+ const label = getLabelFromSource(element);
22
+ // Temporarily remove design-mode-selected class to get original styles
23
+ const wasSelected = element.classList.contains("design-mode-selected");
24
+ if (wasSelected) {
25
+ element.classList.remove("design-mode-selected");
26
+ }
27
+ const styles = getElementStyles(element);
28
+ // Restore design-mode-selected class if it was present
29
+ if (wasSelected) {
30
+ element.classList.add("design-mode-selected");
31
+ }
32
+ // Source location metadata injected at compile time (babel-plugin-enhanced-locator)
33
+ const debugSource = getSourceFromDataAttributes(element);
34
+ // Send message to parent window
35
+ try {
36
+ if (window.parent !== window) {
37
+ window.parent.postMessage({
38
+ type: "component-selected",
39
+ component: {
40
+ name: label,
41
+ element: {
42
+ tagName: element.tagName,
43
+ classList: Array.from(element.classList),
44
+ id: element.id || "",
45
+ },
46
+ styles: {
47
+ ...styles,
48
+ },
49
+ debugSource: debugSource,
50
+ },
51
+ }, "*");
52
+ }
53
+ }
54
+ catch (error) {
55
+ console.log("Could not notify extension:", error);
56
+ }
57
+ // Store in global for polling fallback
58
+ window.selectedComponentInfo =
59
+ {
60
+ name: label,
61
+ element: element,
62
+ classList: Array.from(element.classList),
63
+ id: element.id || "no-id",
64
+ tagName: element.tagName,
65
+ };
66
+ }
67
+ /**
68
+ * Notify the extension about a text change
69
+ * @param element - The element that changed
70
+ * @param originalText - The original text
71
+ * @param newText - The new text
72
+ */
73
+ notifyTextChange(element, originalText, newText) {
74
+ const label = getLabelFromSource(element);
75
+ try {
76
+ if (window.parent !== window) {
77
+ window.parent.postMessage({
78
+ type: "text-changed",
79
+ change: {
80
+ component: { name: label },
81
+ element: {
82
+ tagName: element.tagName,
83
+ classList: Array.from(element.classList),
84
+ id: element.id || "",
85
+ originalText: originalText,
86
+ newText: newText,
87
+ },
88
+ },
89
+ }, "*");
90
+ }
91
+ }
92
+ catch (error) {
93
+ console.log("Could not notify extension about text change:", error);
94
+ }
95
+ }
96
+ /**
97
+ * Notify the parent window that interactions initialization is complete
98
+ */
99
+ notifyInitializationComplete() {
100
+ try {
101
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
102
+ window.parent.postMessage({
103
+ type: "interactions-initialized",
104
+ }, "*");
105
+ }
106
+ }
107
+ catch (error) {
108
+ const err = error;
109
+ console.warn("Could not send initialization message to parent:", err.message);
110
+ }
111
+ }
112
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Component Matcher Module
8
+ * Handles mapping DOM elements to source-locatable elements (data-source-*).
9
+ */
10
+ export declare class ComponentMatcher {
11
+ /**
12
+ * Check whether an element contains compile-time source metadata attributes.
13
+ * @param element - The element to check
14
+ * @returns True if the data-source-file attribute is present
15
+ */
16
+ hasSourceMetadata(element: HTMLElement | null | undefined): boolean;
17
+ /**
18
+ * Checks if a label represents a component name (not a fallback like tag name, ID, or text content)
19
+ * @param label - The label to check
20
+ * @param tagName - The element's tag name (lowercase)
21
+ * @returns True if the label is a component name
22
+ */
23
+ isComponentNameLabel(label: string, tagName: string): boolean;
24
+ /**
25
+ * Check if an element is highlightable.
26
+ * @param element - The element to check
27
+ * @returns True if the element should be highlighted
28
+ */
29
+ isHighlightableElement(element: HTMLElement | null | undefined): boolean;
30
+ /**
31
+ * Find the nearest highlightable element by walking up the DOM tree
32
+ * @param target - The target element
33
+ * @returns The highlightable element or null
34
+ */
35
+ findHighlightableElement(target: HTMLElement | null | undefined): HTMLElement | null;
36
+ }
37
+ //# sourceMappingURL=componentMatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"componentMatcher.d.ts","sourceRoot":"","sources":["../../../src/design/interactions/componentMatcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,qBAAa,gBAAgB;IAC5B;;;;OAIG;IACH,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAOnE;;;;;OAKG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAM7D;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAOxE;;;;OAIG;IACH,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI;CA0BpF"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Component Matcher Module
8
+ * Handles mapping DOM elements to source-locatable elements (data-source-*).
9
+ */
10
+ export class ComponentMatcher {
11
+ /**
12
+ * Check whether an element contains compile-time source metadata attributes.
13
+ * @param element - The element to check
14
+ * @returns True if the data-source-file attribute is present
15
+ */
16
+ hasSourceMetadata(element) {
17
+ if (!element) {
18
+ return false;
19
+ }
20
+ return element.hasAttribute("data-source-file");
21
+ }
22
+ /**
23
+ * Checks if a label represents a component name (not a fallback like tag name, ID, or text content)
24
+ * @param label - The label to check
25
+ * @param tagName - The element's tag name (lowercase)
26
+ * @returns True if the label is a component name
27
+ */
28
+ isComponentNameLabel(label, tagName) {
29
+ return (label !== tagName && !label.includes("#") && !label.includes("(") && !label.includes('"'));
30
+ }
31
+ /**
32
+ * Check if an element is highlightable.
33
+ * @param element - The element to check
34
+ * @returns True if the element should be highlighted
35
+ */
36
+ isHighlightableElement(element) {
37
+ if (!element || element === document.body || element === document.documentElement) {
38
+ return false;
39
+ }
40
+ return this.hasSourceMetadata(element);
41
+ }
42
+ /**
43
+ * Find the nearest highlightable element by walking up the DOM tree
44
+ * @param target - The target element
45
+ * @returns The highlightable element or null
46
+ */
47
+ findHighlightableElement(target) {
48
+ if (!target || target === document.body || target === document.documentElement) {
49
+ return null;
50
+ }
51
+ // Fast path: use closest() if supported.
52
+ const closest = typeof target.closest === "function"
53
+ ? target.closest("[data-source-file]")
54
+ : null;
55
+ if (closest && closest !== document.body && closest !== document.documentElement) {
56
+ return closest;
57
+ }
58
+ // Fallback: manual walk.
59
+ let current = target;
60
+ while (current && current !== document.body && current !== document.documentElement) {
61
+ if (this.isHighlightableElement(current)) {
62
+ return current;
63
+ }
64
+ current = current.parentElement;
65
+ }
66
+ return null;
67
+ }
68
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Editable Manager Module
8
+ * Handles making elements editable and notifying the extension of text changes.
9
+ * History/undo for style changes is owned by the design property panel (host); this module does not use history.
10
+ */
11
+ interface CommunicationManagerLike {
12
+ notifyTextChange: (element: HTMLElement, originalText: string, newText: string) => void;
13
+ }
14
+ export declare class EditableManager {
15
+ private communicationManager?;
16
+ private textTags;
17
+ private boundHandleBlur;
18
+ private boundHandleKeydown;
19
+ constructor(communicationManager?: CommunicationManagerLike);
20
+ /**
21
+ * Make an element editable if it's a text element
22
+ * @param element - The element to make editable
23
+ */
24
+ makeEditableIfText(element: HTMLElement): void;
25
+ /**
26
+ * Remove editable state from an element
27
+ * @param element - The element to make non-editable
28
+ */
29
+ removeEditable(element: HTMLElement): void;
30
+ /**
31
+ * Check if an element is a text element that can be made editable
32
+ * @private
33
+ * @param element - The element to check
34
+ * @returns True if the element can be made editable
35
+ */
36
+ private _isTextElement;
37
+ /**
38
+ * Handle blur event on editable element
39
+ * @private
40
+ * @param e - The blur event
41
+ */
42
+ private _handleBlur;
43
+ /**
44
+ * Handle keydown event on editable element
45
+ * @private
46
+ * @param e - The keydown event
47
+ */
48
+ private _handleKeydown;
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=editableManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editableManager.d.ts","sourceRoot":"","sources":["../../../src/design/interactions/editableManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AAEH,UAAU,wBAAwB;IACjC,gBAAgB,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxF;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,oBAAoB,CAAC,CAA2B;IACxD,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,kBAAkB,CAA6B;gBAE3C,oBAAoB,CAAC,EAAE,wBAAwB;IAO3D;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAY9C;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAS1C;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAkBnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAetB"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ export class EditableManager {
7
+ communicationManager;
8
+ textTags;
9
+ boundHandleBlur;
10
+ boundHandleKeydown;
11
+ constructor(communicationManager) {
12
+ this.communicationManager = communicationManager;
13
+ this.textTags = ["H1", "H2", "H3", "H4", "H5", "H6", "P", "SPAN", "A", "BUTTON", "LABEL"];
14
+ this.boundHandleBlur = this._handleBlur.bind(this);
15
+ this.boundHandleKeydown = this._handleKeydown.bind(this);
16
+ }
17
+ /**
18
+ * Make an element editable if it's a text element
19
+ * @param element - The element to make editable
20
+ */
21
+ makeEditableIfText(element) {
22
+ if (!this._isTextElement(element)) {
23
+ return;
24
+ }
25
+ element.contentEditable = "true";
26
+ element.dataset.originalText = element.textContent ?? "";
27
+ element.addEventListener("blur", this.boundHandleBlur);
28
+ element.addEventListener("keydown", this.boundHandleKeydown);
29
+ }
30
+ /**
31
+ * Remove editable state from an element
32
+ * @param element - The element to make non-editable
33
+ */
34
+ removeEditable(element) {
35
+ if (element.contentEditable === "true") {
36
+ element.contentEditable = "false";
37
+ }
38
+ delete element.dataset.originalText;
39
+ element.removeEventListener("blur", this.boundHandleBlur);
40
+ element.removeEventListener("keydown", this.boundHandleKeydown);
41
+ }
42
+ /**
43
+ * Check if an element is a text element that can be made editable
44
+ * @private
45
+ * @param element - The element to check
46
+ * @returns True if the element can be made editable
47
+ */
48
+ _isTextElement(element) {
49
+ return (this.textTags.includes(element.tagName) &&
50
+ (element.textContent ?? "").trim().length > 0 &&
51
+ element.dataset.textType === "static");
52
+ }
53
+ /**
54
+ * Handle blur event on editable element
55
+ * @private
56
+ * @param e - The blur event
57
+ */
58
+ _handleBlur(e) {
59
+ const element = e.target;
60
+ const newText = element.textContent ?? "";
61
+ const originalText = element.dataset.originalText ?? "";
62
+ if (newText !== originalText) {
63
+ // Mirror JS behavior: update stored originalText after a commit
64
+ element.dataset.originalText = newText;
65
+ // Notify extension about text change (if available)
66
+ if (this.communicationManager) {
67
+ this.communicationManager.notifyTextChange(element, originalText, newText);
68
+ }
69
+ }
70
+ this.removeEditable(element);
71
+ }
72
+ /**
73
+ * Handle keydown event on editable element
74
+ * @private
75
+ * @param e - The keydown event
76
+ */
77
+ _handleKeydown(e) {
78
+ const element = e.target;
79
+ if (e.key === "Enter" && !e.shiftKey) {
80
+ e.preventDefault();
81
+ element.blur();
82
+ }
83
+ if (e.key === "Escape") {
84
+ if (element.dataset.originalText) {
85
+ element.textContent = element.dataset.originalText;
86
+ }
87
+ element.blur();
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Event Handlers Module
8
+ * Handles mouse and click events for highlighting
9
+ */
10
+ interface ComponentMatcherLike {
11
+ findHighlightableElement: (target: HTMLElement) => HTMLElement | null;
12
+ }
13
+ interface StyleManagerLike {
14
+ highlightElement: (element: HTMLElement) => void;
15
+ unhighlightElement: (element: HTMLElement) => void;
16
+ selectElement: (element: HTMLElement) => void;
17
+ deselectElement: (element: HTMLElement) => void;
18
+ }
19
+ interface EditableManagerLike {
20
+ makeEditableIfText: (element: HTMLElement) => void;
21
+ removeEditable: (element: HTMLElement) => void;
22
+ }
23
+ interface CommunicationManagerLike {
24
+ notifyComponentSelected: (element: HTMLElement) => void;
25
+ }
26
+ export declare class EventHandlers {
27
+ private isInteractionsActive;
28
+ private componentMatcher;
29
+ private styleManager;
30
+ private editableManager;
31
+ private communicationManager;
32
+ private currentHighlighted;
33
+ private selectedElement;
34
+ constructor(isInteractionsActive: () => boolean, componentMatcher: ComponentMatcherLike, styleManager: StyleManagerLike, editableManager: EditableManagerLike, communicationManager: CommunicationManagerLike);
35
+ /**
36
+ * Find the nearest highlightable element by walking up the DOM tree
37
+ * @param target - The target element
38
+ * @returns The highlightable element or null
39
+ */
40
+ private _findHighlightableElement;
41
+ /**
42
+ * Handle mouseover event
43
+ * @param e - The mouseover event
44
+ */
45
+ handleMouseOver(e: MouseEvent): void;
46
+ /**
47
+ * Handle mouseleave event
48
+ */
49
+ handleMouseLeave(): void;
50
+ /**
51
+ * Handle click event
52
+ * @param e - The click event
53
+ */
54
+ handleClick(e: MouseEvent): void;
55
+ /**
56
+ * Clear all highlights and selections
57
+ */
58
+ clearAll(): void;
59
+ /**
60
+ * Get the currently selected element
61
+ * @returns The selected element
62
+ */
63
+ getSelectedElement(): HTMLElement | null;
64
+ }
65
+ export {};
66
+ //# sourceMappingURL=eventHandlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventHandlers.d.ts","sourceRoot":"","sources":["../../../src/design/interactions/eventHandlers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,UAAU,oBAAoB;IAC7B,wBAAwB,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;CACtE;AAED,UAAU,gBAAgB;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,kBAAkB,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAC9C,eAAe,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAChD;AAED,UAAU,mBAAmB;IAC5B,kBAAkB,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,cAAc,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAED,UAAU,wBAAwB;IACjC,uBAAuB,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,aAAa;IACzB,OAAO,CAAC,oBAAoB,CAAgB;IAC5C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,oBAAoB,CAA2B;IAEvD,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,eAAe,CAAqB;gBAG3C,oBAAoB,EAAE,MAAM,OAAO,EACnC,gBAAgB,EAAE,oBAAoB,EACtC,YAAY,EAAE,gBAAgB,EAC9B,eAAe,EAAE,mBAAmB,EACpC,oBAAoB,EAAE,wBAAwB;IAiB/C;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;IAIjC;;;OAGG;IACH,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI;IAmCpC;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAcxB;;;OAGG;IACH,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI;IA6ChC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAahB;;;OAGG;IACH,kBAAkB,IAAI,WAAW,GAAG,IAAI;CAGxC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ export class EventHandlers {
7
+ isInteractionsActive;
8
+ componentMatcher;
9
+ styleManager;
10
+ editableManager;
11
+ communicationManager;
12
+ currentHighlighted;
13
+ selectedElement;
14
+ constructor(isInteractionsActive, componentMatcher, styleManager, editableManager, communicationManager) {
15
+ this.isInteractionsActive = isInteractionsActive;
16
+ this.componentMatcher = componentMatcher;
17
+ this.styleManager = styleManager;
18
+ this.editableManager = editableManager;
19
+ this.communicationManager = communicationManager;
20
+ this.currentHighlighted = null;
21
+ this.selectedElement = null;
22
+ // Bind methods to preserve 'this' context
23
+ this.handleMouseOver = this.handleMouseOver.bind(this);
24
+ this.handleMouseLeave = this.handleMouseLeave.bind(this);
25
+ this.handleClick = this.handleClick.bind(this);
26
+ }
27
+ /**
28
+ * Find the nearest highlightable element by walking up the DOM tree
29
+ * @param target - The target element
30
+ * @returns The highlightable element or null
31
+ */
32
+ _findHighlightableElement(target) {
33
+ return this.componentMatcher.findHighlightableElement(target);
34
+ }
35
+ /**
36
+ * Handle mouseover event
37
+ * @param e - The mouseover event
38
+ */
39
+ handleMouseOver(e) {
40
+ if (!this.isInteractionsActive()) {
41
+ return;
42
+ }
43
+ e.stopPropagation();
44
+ const target = e.target;
45
+ if (target.nodeType !== 1 || target.tagName === "HTML" || target.tagName === "BODY") {
46
+ return;
47
+ }
48
+ const element = this._findHighlightableElement(target);
49
+ if (!element) {
50
+ return;
51
+ }
52
+ if (this.currentHighlighted === element ||
53
+ (this.selectedElement && this.selectedElement === element)) {
54
+ return;
55
+ }
56
+ if (this.currentHighlighted &&
57
+ !this.currentHighlighted.classList.contains("design-mode-selected")) {
58
+ this.styleManager.unhighlightElement(this.currentHighlighted);
59
+ }
60
+ this.styleManager.highlightElement(element);
61
+ this.currentHighlighted = element;
62
+ }
63
+ /**
64
+ * Handle mouseleave event
65
+ */
66
+ handleMouseLeave() {
67
+ if (!this.isInteractionsActive()) {
68
+ return;
69
+ }
70
+ if (this.currentHighlighted &&
71
+ !this.currentHighlighted.classList.contains("design-mode-selected")) {
72
+ this.styleManager.unhighlightElement(this.currentHighlighted);
73
+ this.currentHighlighted = null;
74
+ }
75
+ }
76
+ /**
77
+ * Handle click event
78
+ * @param e - The click event
79
+ */
80
+ handleClick(e) {
81
+ if (!this.isInteractionsActive()) {
82
+ return;
83
+ }
84
+ e.preventDefault();
85
+ e.stopPropagation();
86
+ const target = e.target;
87
+ if (target.nodeType !== 1 || target.tagName === "HTML" || target.tagName === "BODY") {
88
+ return;
89
+ }
90
+ const element = this._findHighlightableElement(target);
91
+ if (!element) {
92
+ return;
93
+ }
94
+ if (this.selectedElement && this.selectedElement === element) {
95
+ return;
96
+ }
97
+ // Deselect previous element
98
+ if (this.selectedElement) {
99
+ this.styleManager.deselectElement(this.selectedElement);
100
+ this.editableManager.removeEditable(this.selectedElement);
101
+ }
102
+ // Remove highlight from current highlighted
103
+ if (this.currentHighlighted) {
104
+ this.styleManager.unhighlightElement(this.currentHighlighted);
105
+ this.currentHighlighted = null;
106
+ }
107
+ // Select new element
108
+ this.selectedElement = element;
109
+ this.styleManager.selectElement(element);
110
+ // Make text elements editable
111
+ this.editableManager.makeEditableIfText(element);
112
+ // Notify extension
113
+ this.communicationManager.notifyComponentSelected(element);
114
+ }
115
+ /**
116
+ * Clear all highlights and selections
117
+ */
118
+ clearAll() {
119
+ if (this.currentHighlighted) {
120
+ this.styleManager.unhighlightElement(this.currentHighlighted);
121
+ this.currentHighlighted = null;
122
+ }
123
+ if (this.selectedElement) {
124
+ this.styleManager.deselectElement(this.selectedElement);
125
+ this.editableManager.removeEditable(this.selectedElement);
126
+ this.selectedElement = null;
127
+ }
128
+ }
129
+ /**
130
+ * Get the currently selected element
131
+ * @returns The selected element
132
+ */
133
+ getSelectedElement() {
134
+ return this.selectedElement;
135
+ }
136
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/design/interactions/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ /**
7
+ * Entry point for bundling the design mode interactions
8
+ * This file is used by esbuild to create the bundled version
9
+ */
10
+ import { InteractionsController } from "./interactionsController.js";
11
+ const interactions = new InteractionsController(true);
12
+ if (typeof document !== "undefined") {
13
+ if (document.readyState === "loading") {
14
+ document.addEventListener("DOMContentLoaded", () => {
15
+ interactions.initialize();
16
+ });
17
+ }
18
+ else {
19
+ interactions.initialize();
20
+ }
21
+ }
22
+ // Expose global functions
23
+ if (typeof window !== "undefined") {
24
+ window.enableInteractions = function () {
25
+ interactions.enable();
26
+ };
27
+ window.disableInteractions = function () {
28
+ interactions.disable();
29
+ };
30
+ window.addEventListener("message", function (event) {
31
+ const data = event.data;
32
+ const typed = data && typeof data === "object"
33
+ ? data
34
+ : null;
35
+ if (typed && typed.type === "style-change") {
36
+ interactions.applyStyleChange(String(typed.property ?? ""), String(typed.value ?? ""));
37
+ }
38
+ if (typed && typed.type === "enable-interactions") {
39
+ window.enableInteractions?.();
40
+ }
41
+ if (typed && typed.type === "disable-interactions") {
42
+ window.disableInteractions?.();
43
+ }
44
+ });
45
+ }