@livetemplate/client 0.8.12 → 0.8.13
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/dom/directives.d.ts +7 -5
- package/dist/dom/directives.d.ts.map +1 -1
- package/dist/dom/directives.js +31 -17
- package/dist/dom/directives.js.map +1 -1
- package/dist/dom/event-delegation.d.ts +5 -3
- package/dist/dom/event-delegation.d.ts.map +1 -1
- package/dist/dom/event-delegation.js +62 -177
- package/dist/dom/event-delegation.js.map +1 -1
- package/dist/dom/link-interceptor.js +1 -1
- package/dist/dom/link-interceptor.js.map +1 -1
- package/dist/dom/reactive-attributes.d.ts +15 -20
- package/dist/dom/reactive-attributes.d.ts.map +1 -1
- package/dist/dom/reactive-attributes.js +78 -81
- package/dist/dom/reactive-attributes.js.map +1 -1
- package/dist/livetemplate-client.browser.js +4 -4
- package/dist/livetemplate-client.browser.js.map +4 -4
- package/dist/livetemplate-client.d.ts +0 -2
- package/dist/livetemplate-client.d.ts.map +1 -1
- package/dist/livetemplate-client.js +3 -12
- package/dist/livetemplate-client.js.map +1 -1
- package/dist/state/form-lifecycle-manager.d.ts +1 -3
- package/dist/state/form-lifecycle-manager.d.ts.map +1 -1
- package/dist/state/form-lifecycle-manager.js +6 -6
- package/dist/state/form-lifecycle-manager.js.map +1 -1
- package/dist/tests/directives.test.js +33 -33
- package/dist/tests/directives.test.js.map +1 -1
- package/dist/tests/event-delegation.test.js +7 -9
- package/dist/tests/event-delegation.test.js.map +1 -1
- package/dist/tests/form-lifecycle-manager.test.js +27 -28
- package/dist/tests/form-lifecycle-manager.test.js.map +1 -1
- package/dist/tests/reactive-attributes.test.js +60 -84
- package/dist/tests/reactive-attributes.test.js.map +1 -1
- package/dist/utils/lvt-selector.d.ts +3 -0
- package/dist/utils/lvt-selector.d.ts.map +1 -0
- package/dist/utils/lvt-selector.js +13 -0
- package/dist/utils/lvt-selector.js.map +1 -0
- package/package.json +1 -1
- package/dist/dom/modal-manager.d.ts +0 -11
- package/dist/dom/modal-manager.d.ts.map +0 -1
- package/dist/dom/modal-manager.js +0 -62
- package/dist/dom/modal-manager.js.map +0 -1
- package/dist/tests/modal-manager.test.d.ts +0 -2
- package/dist/tests/modal-manager.test.d.ts.map +0 -1
- package/dist/tests/modal-manager.test.js +0 -80
- package/dist/tests/modal-manager.test.js.map +0 -1
- package/dist/utils/confirm.d.ts +0 -12
- package/dist/utils/confirm.d.ts.map +0 -1
- package/dist/utils/confirm.js +0 -35
- package/dist/utils/confirm.js.map +0 -1
package/dist/dom/directives.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Apply scroll directives on elements with lvt-scroll attributes.
|
|
3
|
-
*/
|
|
4
1
|
export declare function handleScrollDirectives(rootElement: Element): void;
|
|
5
2
|
/**
|
|
6
|
-
* Apply highlight directives to elements with lvt-highlight attributes.
|
|
3
|
+
* Apply highlight directives to elements with lvt-fx:highlight attributes.
|
|
4
|
+
* Configuration read from CSS custom properties:
|
|
5
|
+
* --lvt-highlight-duration: <ms> (default: 500)
|
|
6
|
+
* --lvt-highlight-color: <color> (default: #ffc107)
|
|
7
7
|
*/
|
|
8
8
|
export declare function handleHighlightDirectives(rootElement: Element): void;
|
|
9
9
|
/**
|
|
10
|
-
* Apply animation directives to elements with lvt-animate attributes.
|
|
10
|
+
* Apply animation directives to elements with lvt-fx:animate attributes.
|
|
11
|
+
* Configuration read from CSS custom properties:
|
|
12
|
+
* --lvt-animate-duration: <ms> (default: 300)
|
|
11
13
|
*/
|
|
12
14
|
export declare function handleAnimateDirectives(rootElement: Element): void;
|
|
13
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":"AAQA,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAuDjE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA6BpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA0ElE;AAkBD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA4BhE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAW7C"}
|
package/dist/dom/directives.js
CHANGED
|
@@ -6,16 +6,23 @@ exports.handleAnimateDirectives = handleAnimateDirectives;
|
|
|
6
6
|
exports.handleToastDirectives = handleToastDirectives;
|
|
7
7
|
exports.setupToastClickOutside = setupToastClickOutside;
|
|
8
8
|
/**
|
|
9
|
-
* Apply scroll directives on elements with lvt-scroll attributes.
|
|
9
|
+
* Apply scroll directives on elements with lvt-fx:scroll attributes.
|
|
10
|
+
* Configuration read from CSS custom properties:
|
|
11
|
+
* --lvt-scroll-behavior: auto | smooth (default: auto)
|
|
12
|
+
* --lvt-scroll-threshold: <number> (default: 100)
|
|
10
13
|
*/
|
|
14
|
+
const VALID_SCROLL_BEHAVIORS = new Set(["auto", "smooth", "instant"]);
|
|
11
15
|
function handleScrollDirectives(rootElement) {
|
|
12
|
-
const scrollElements = rootElement.querySelectorAll("[lvt-scroll]");
|
|
16
|
+
const scrollElements = rootElement.querySelectorAll("[lvt-fx\\:scroll]");
|
|
13
17
|
scrollElements.forEach((element) => {
|
|
14
18
|
const htmlElement = element;
|
|
15
|
-
const mode = htmlElement.getAttribute("lvt-scroll");
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
+
const mode = htmlElement.getAttribute("lvt-fx:scroll");
|
|
20
|
+
const computed = getComputedStyle(htmlElement);
|
|
21
|
+
const rawBehavior = computed.getPropertyValue("--lvt-scroll-behavior").trim();
|
|
22
|
+
const behavior = VALID_SCROLL_BEHAVIORS.has(rawBehavior)
|
|
23
|
+
? rawBehavior
|
|
24
|
+
: "auto";
|
|
25
|
+
const threshold = parseInt(computed.getPropertyValue("--lvt-scroll-threshold").trim() || "100", 10);
|
|
19
26
|
if (!mode)
|
|
20
27
|
return;
|
|
21
28
|
switch (mode) {
|
|
@@ -47,19 +54,23 @@ function handleScrollDirectives(rootElement) {
|
|
|
47
54
|
case "preserve":
|
|
48
55
|
break;
|
|
49
56
|
default:
|
|
50
|
-
console.warn(`Unknown lvt-scroll mode: ${mode}`);
|
|
57
|
+
console.warn(`Unknown lvt-fx:scroll mode: ${mode}`);
|
|
51
58
|
}
|
|
52
59
|
});
|
|
53
60
|
}
|
|
54
61
|
/**
|
|
55
|
-
* Apply highlight directives to elements with lvt-highlight attributes.
|
|
62
|
+
* Apply highlight directives to elements with lvt-fx:highlight attributes.
|
|
63
|
+
* Configuration read from CSS custom properties:
|
|
64
|
+
* --lvt-highlight-duration: <ms> (default: 500)
|
|
65
|
+
* --lvt-highlight-color: <color> (default: #ffc107)
|
|
56
66
|
*/
|
|
57
67
|
function handleHighlightDirectives(rootElement) {
|
|
58
|
-
const highlightElements = rootElement.querySelectorAll("[lvt-highlight]");
|
|
68
|
+
const highlightElements = rootElement.querySelectorAll("[lvt-fx\\:highlight]");
|
|
59
69
|
highlightElements.forEach((element) => {
|
|
60
|
-
const mode = element.getAttribute("lvt-highlight");
|
|
61
|
-
const
|
|
62
|
-
const
|
|
70
|
+
const mode = element.getAttribute("lvt-fx:highlight");
|
|
71
|
+
const computed = getComputedStyle(element);
|
|
72
|
+
const duration = parseInt(computed.getPropertyValue("--lvt-highlight-duration").trim() || "500", 10);
|
|
73
|
+
const color = computed.getPropertyValue("--lvt-highlight-color").trim() || "#ffc107";
|
|
63
74
|
if (!mode)
|
|
64
75
|
return;
|
|
65
76
|
const htmlElement = element;
|
|
@@ -76,13 +87,16 @@ function handleHighlightDirectives(rootElement) {
|
|
|
76
87
|
});
|
|
77
88
|
}
|
|
78
89
|
/**
|
|
79
|
-
* Apply animation directives to elements with lvt-animate attributes.
|
|
90
|
+
* Apply animation directives to elements with lvt-fx:animate attributes.
|
|
91
|
+
* Configuration read from CSS custom properties:
|
|
92
|
+
* --lvt-animate-duration: <ms> (default: 300)
|
|
80
93
|
*/
|
|
81
94
|
function handleAnimateDirectives(rootElement) {
|
|
82
|
-
const animateElements = rootElement.querySelectorAll("[lvt-animate]");
|
|
95
|
+
const animateElements = rootElement.querySelectorAll("[lvt-fx\\:animate]");
|
|
83
96
|
animateElements.forEach((element) => {
|
|
84
|
-
const animation = element.getAttribute("lvt-animate");
|
|
85
|
-
const
|
|
97
|
+
const animation = element.getAttribute("lvt-fx:animate");
|
|
98
|
+
const computed = getComputedStyle(element);
|
|
99
|
+
const duration = parseInt(computed.getPropertyValue("--lvt-animate-duration").trim() || "300", 10);
|
|
86
100
|
if (!animation)
|
|
87
101
|
return;
|
|
88
102
|
const htmlElement = element;
|
|
@@ -98,7 +112,7 @@ function handleAnimateDirectives(rootElement) {
|
|
|
98
112
|
htmlElement.style.animation = `lvt-scale-in var(--lvt-animate-duration) ease-out`;
|
|
99
113
|
break;
|
|
100
114
|
default:
|
|
101
|
-
console.warn(`Unknown lvt-animate mode: ${animation}`);
|
|
115
|
+
console.warn(`Unknown lvt-fx:animate mode: ${animation}`);
|
|
102
116
|
}
|
|
103
117
|
htmlElement.addEventListener("animationend", () => {
|
|
104
118
|
htmlElement.style.animation = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directives.js","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"directives.js","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,6 @@ export interface EventDelegationContext {
|
|
|
5
5
|
parseValue(value: string): any;
|
|
6
6
|
send(message: any): void;
|
|
7
7
|
setActiveSubmission(form: HTMLFormElement | null, button: HTMLButtonElement | null, originalButtonText: string | null): void;
|
|
8
|
-
openModal(modalId: string): void;
|
|
9
|
-
closeModal(modalId: string): void;
|
|
10
8
|
getWebSocketReadyState(): number | undefined;
|
|
11
9
|
triggerPendingUploads(uploadName: string): void;
|
|
12
10
|
}
|
|
@@ -20,8 +18,12 @@ export declare class EventDelegator {
|
|
|
20
18
|
private extractButtonData;
|
|
21
19
|
setupEventDelegation(): void;
|
|
22
20
|
setupWindowEventDelegation(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Sets up click-away detection for lvt-el:*:on:click-away attributes.
|
|
23
|
+
* Instead of routing to a server action, click-away triggers client-side
|
|
24
|
+
* DOM manipulation via executeAction from reactive-attributes.
|
|
25
|
+
*/
|
|
23
26
|
setupClickAwayDelegation(): void;
|
|
24
|
-
setupModalDelegation(): void;
|
|
25
27
|
/**
|
|
26
28
|
* Sets up focus trapping for elements with lvt-focus-trap attribute.
|
|
27
29
|
* Focus is trapped within the element, cycling through focusable elements
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-delegation.d.ts","sourceRoot":"","sources":["../../dom/event-delegation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-delegation.d.ts","sourceRoot":"","sources":["../../dom/event-delegation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAa9C,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,IAAI,OAAO,GAAG,IAAI,CAAC;IACpC,sBAAsB,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC;IACzB,mBAAmB,CACjB,IAAI,EAAE,eAAe,GAAG,IAAI,EAC5B,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,kBAAkB,EAAE,MAAM,GAAG,IAAI,GAChC,IAAI,CAAC;IACR,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAAC;IAC7C,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACjD;AAED;;GAEG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,sBAAsB,EAC/B,MAAM,EAAE,MAAM;IAGjC,OAAO,CAAC,iBAAiB;IAYzB,oBAAoB,IAAI,IAAI;IA8X5B,0BAA0B,IAAI,IAAI;IA8FlC;;;;OAIG;IACH,wBAAwB,IAAI,IAAI;IAuChC;;;;OAIG;IACH,wBAAwB,IAAI,IAAI;IAmGhC;;;;OAIG;IACH,wBAAwB,IAAI,IAAI;CA0GjC"}
|
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EventDelegator = void 0;
|
|
4
4
|
const rate_limit_1 = require("../utils/rate-limit");
|
|
5
|
-
const
|
|
5
|
+
const lvt_selector_1 = require("../utils/lvt-selector");
|
|
6
|
+
const reactive_attributes_1 = require("./reactive-attributes");
|
|
7
|
+
// Methods supported by click-away, derived from ReactiveAction values
|
|
8
|
+
const CLICK_AWAY_METHOD_MAP = {
|
|
9
|
+
reset: "reset",
|
|
10
|
+
addclass: "addClass",
|
|
11
|
+
removeclass: "removeClass",
|
|
12
|
+
toggleclass: "toggleClass",
|
|
13
|
+
setattr: "setAttr",
|
|
14
|
+
toggleattr: "toggleAttr",
|
|
15
|
+
};
|
|
16
|
+
const CLICK_AWAY_METHODS = Object.keys(CLICK_AWAY_METHOD_MAP);
|
|
6
17
|
/**
|
|
7
18
|
* Handles all DOM event delegation concerns for LiveTemplateClient.
|
|
8
19
|
*/
|
|
@@ -75,7 +86,7 @@ class EventDelegator {
|
|
|
75
86
|
}
|
|
76
87
|
if (!inWrapper)
|
|
77
88
|
return;
|
|
78
|
-
const attrName = `lvt
|
|
89
|
+
const attrName = `lvt-on:${eventType}`;
|
|
79
90
|
element = target;
|
|
80
91
|
while (element && element !== currentWrapper.parentElement) {
|
|
81
92
|
let action = element.getAttribute(attrName);
|
|
@@ -92,7 +103,7 @@ class EventDelegator {
|
|
|
92
103
|
// Orphan button detection (Tier 1: formless standalone buttons).
|
|
93
104
|
// A <button name="action"> outside any form triggers the named action directly.
|
|
94
105
|
// Resolution order for click events:
|
|
95
|
-
// 1. lvt-click attribute (Tier 2 — already checked above)
|
|
106
|
+
// 1. lvt-on:click attribute (Tier 2 — already checked above)
|
|
96
107
|
// 2. Orphan button name (Tier 1 — checked here)
|
|
97
108
|
if (!action && eventType === "click") {
|
|
98
109
|
const btn = element instanceof HTMLButtonElement ? element : null;
|
|
@@ -107,13 +118,13 @@ class EventDelegator {
|
|
|
107
118
|
isOrphanButton = true;
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
|
-
// Auto-intercept forms
|
|
121
|
+
// Auto-intercept forms (progressive complexity).
|
|
111
122
|
// Button name IS the action. Resolution order:
|
|
112
123
|
// 1. submitter.name (button name = action)
|
|
113
124
|
// 2. form.name (form name = action)
|
|
114
125
|
// 3. "" (server defaults to Submit())
|
|
115
126
|
if (!action && eventType === "submit" && element instanceof HTMLFormElement) {
|
|
116
|
-
if (!element.hasAttribute("lvt-no-intercept")) {
|
|
127
|
+
if (!element.hasAttribute("lvt-form:no-intercept")) {
|
|
117
128
|
const submitter = e.submitter;
|
|
118
129
|
if (submitter instanceof HTMLButtonElement && submitter.name) {
|
|
119
130
|
action = submitter.name;
|
|
@@ -136,22 +147,6 @@ class EventDelegator {
|
|
|
136
147
|
}
|
|
137
148
|
}
|
|
138
149
|
}
|
|
139
|
-
if (!action && (eventType === "change" || eventType === "input" || eventType === "search")) {
|
|
140
|
-
// For input/search events, also check lvt-change on the element itself
|
|
141
|
-
// This handles: typing (input), clearing via X button (search/input), blur (change)
|
|
142
|
-
if ((eventType === "input" || eventType === "search") && element.hasAttribute("lvt-change")) {
|
|
143
|
-
action = element.getAttribute("lvt-change");
|
|
144
|
-
actionElement = element;
|
|
145
|
-
}
|
|
146
|
-
// Check for form-level lvt-change
|
|
147
|
-
if (!action) {
|
|
148
|
-
const formElement = element.closest("form");
|
|
149
|
-
if (formElement && formElement.hasAttribute("lvt-change")) {
|
|
150
|
-
action = formElement.getAttribute("lvt-change");
|
|
151
|
-
actionElement = formElement;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
150
|
if (action != null && actionElement) {
|
|
156
151
|
if (eventType === "submit") {
|
|
157
152
|
window.__lvtActionFound = action;
|
|
@@ -176,11 +171,6 @@ class EventDelegator {
|
|
|
176
171
|
eventType,
|
|
177
172
|
targetElement,
|
|
178
173
|
});
|
|
179
|
-
// Handle lvt-confirm for any action
|
|
180
|
-
if (!(0, confirm_1.checkLvtConfirm)(targetElement)) {
|
|
181
|
-
this.logger.debug("Action cancelled by user:", action);
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
174
|
const message = { action, data: {} };
|
|
185
175
|
if (targetElement instanceof HTMLFormElement) {
|
|
186
176
|
this.logger.debug("Processing form element");
|
|
@@ -193,11 +183,11 @@ class EventDelegator {
|
|
|
193
183
|
// Get password field names to skip parseValue for them
|
|
194
184
|
const passwordFields = new Set(Array.from(targetElement.querySelectorAll('input[type="password"][name]')).map((el) => el.name));
|
|
195
185
|
// Determine which form field key is the action routing key
|
|
196
|
-
// (the submitter button's name, or "action"
|
|
186
|
+
// (the submitter button's name, or "action" field)
|
|
197
187
|
const submitterForData = targetElement.__lvtSubmitter;
|
|
198
188
|
const actionFieldName = submitterForData?.name || "action";
|
|
199
189
|
formData.forEach((value, key) => {
|
|
200
|
-
if (key === actionFieldName || key === "action"
|
|
190
|
+
if (key === actionFieldName || key === "action")
|
|
201
191
|
return;
|
|
202
192
|
if (checkboxNames.has(key)) {
|
|
203
193
|
message.data[key] = true;
|
|
@@ -238,29 +228,28 @@ class EventDelegator {
|
|
|
238
228
|
if (isOrphanButton) {
|
|
239
229
|
this.extractButtonData(actionElement, message.data);
|
|
240
230
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
});
|
|
231
|
+
// Extract standard data-* attributes from the action element.
|
|
232
|
+
// Exclude data-key (list reconciliation) and data-lvt-id (internal framework ID)
|
|
233
|
+
// since these are LiveTemplate internals, not user-provided action data.
|
|
234
|
+
if (!(targetElement instanceof HTMLFormElement) && !isOrphanButton) {
|
|
235
|
+
Array.from(actionElement.attributes).forEach((attr) => {
|
|
236
|
+
if (attr.name.startsWith("data-") && attr.name !== "data-key" && attr.name !== "data-lvt-id") {
|
|
237
|
+
const key = attr.name.slice(5);
|
|
238
|
+
message.data[key] = this.context.parseValue(attr.value);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
253
242
|
if (eventType === "submit" &&
|
|
254
243
|
targetElement instanceof HTMLFormElement) {
|
|
255
244
|
const submitEvent = e;
|
|
256
245
|
const submitButton = submitEvent.submitter;
|
|
257
246
|
let originalButtonText = null;
|
|
258
247
|
if (submitButton &&
|
|
259
|
-
submitButton.hasAttribute("lvt-disable-with")) {
|
|
248
|
+
submitButton.hasAttribute("lvt-form:disable-with")) {
|
|
260
249
|
originalButtonText = submitButton.textContent;
|
|
261
250
|
submitButton.disabled = true;
|
|
262
251
|
submitButton.textContent =
|
|
263
|
-
submitButton.getAttribute("lvt-disable-with");
|
|
252
|
+
submitButton.getAttribute("lvt-form:disable-with");
|
|
264
253
|
this.logger.debug("Disabled submit button");
|
|
265
254
|
}
|
|
266
255
|
this.context.setActiveSubmission(targetElement, submitButton || null, originalButtonText);
|
|
@@ -289,8 +278,8 @@ class EventDelegator {
|
|
|
289
278
|
}
|
|
290
279
|
}
|
|
291
280
|
};
|
|
292
|
-
const throttleValue = actionElement.getAttribute("lvt-throttle");
|
|
293
|
-
const debounceValue = actionElement.getAttribute("lvt-debounce");
|
|
281
|
+
const throttleValue = actionElement.getAttribute("lvt-mod:throttle");
|
|
282
|
+
const debounceValue = actionElement.getAttribute("lvt-mod:debounce");
|
|
294
283
|
// Skip rate limiting for "search" event (clear button click) - it's a discrete action
|
|
295
284
|
const shouldRateLimit = (throttleValue || debounceValue) && eventType !== "search";
|
|
296
285
|
if (shouldRateLimit) {
|
|
@@ -372,8 +361,8 @@ class EventDelegator {
|
|
|
372
361
|
const currentWrapper = this.context.getWrapperElement();
|
|
373
362
|
if (!currentWrapper)
|
|
374
363
|
return;
|
|
375
|
-
const attrName = `lvt-window
|
|
376
|
-
const elements = currentWrapper.querySelectorAll(
|
|
364
|
+
const attrName = `lvt-on:window:${eventType}`;
|
|
365
|
+
const elements = currentWrapper.querySelectorAll((0, lvt_selector_1.lvtSelector)(attrName));
|
|
377
366
|
elements.forEach((element) => {
|
|
378
367
|
const action = element.getAttribute(attrName);
|
|
379
368
|
if (!action)
|
|
@@ -387,20 +376,15 @@ class EventDelegator {
|
|
|
387
376
|
}
|
|
388
377
|
}
|
|
389
378
|
const message = { action, data: {} };
|
|
379
|
+
// Extract standard data-* attributes from element
|
|
390
380
|
Array.from(element.attributes).forEach((attr) => {
|
|
391
|
-
if (attr.name.startsWith("
|
|
392
|
-
const key = attr.name.
|
|
393
|
-
message.data[key] = this.context.parseValue(attr.value);
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
397
|
-
if (attr.name.startsWith("lvt-value-")) {
|
|
398
|
-
const key = attr.name.replace("lvt-value-", "");
|
|
381
|
+
if (attr.name.startsWith("data-") && attr.name !== "data-key" && attr.name !== "data-lvt-id") {
|
|
382
|
+
const key = attr.name.slice(5);
|
|
399
383
|
message.data[key] = this.context.parseValue(attr.value);
|
|
400
384
|
}
|
|
401
385
|
});
|
|
402
|
-
const throttleValue = element.getAttribute("lvt-throttle");
|
|
403
|
-
const debounceValue = element.getAttribute("lvt-debounce");
|
|
386
|
+
const throttleValue = element.getAttribute("lvt-mod:throttle");
|
|
387
|
+
const debounceValue = element.getAttribute("lvt-mod:debounce");
|
|
404
388
|
const handleAction = () => this.context.send(message);
|
|
405
389
|
if (throttleValue || debounceValue) {
|
|
406
390
|
if (!rateLimitedHandlers.has(element)) {
|
|
@@ -435,6 +419,11 @@ class EventDelegator {
|
|
|
435
419
|
window.addEventListener(eventType, listener);
|
|
436
420
|
});
|
|
437
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Sets up click-away detection for lvt-el:*:on:click-away attributes.
|
|
424
|
+
* Instead of routing to a server action, click-away triggers client-side
|
|
425
|
+
* DOM manipulation via executeAction from reactive-attributes.
|
|
426
|
+
*/
|
|
438
427
|
setupClickAwayDelegation() {
|
|
439
428
|
const wrapperElement = this.context.getWrapperElement();
|
|
440
429
|
if (!wrapperElement)
|
|
@@ -450,133 +439,29 @@ class EventDelegator {
|
|
|
450
439
|
if (!currentWrapper)
|
|
451
440
|
return;
|
|
452
441
|
const target = e.target;
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
442
|
+
const clickAwaySelector = CLICK_AWAY_METHODS
|
|
443
|
+
.map(m => (0, lvt_selector_1.lvtSelector)(`lvt-el:${m}:on:click-away`))
|
|
444
|
+
.join(", ");
|
|
445
|
+
const clickAwayElements = currentWrapper.querySelectorAll(clickAwaySelector);
|
|
446
|
+
clickAwayElements.forEach((element) => {
|
|
447
|
+
if (element.contains(target))
|
|
448
|
+
return; // Click was inside, not away
|
|
449
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
450
|
+
if (!attr.name.includes(":on:click-away"))
|
|
458
451
|
return;
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
if (attr.name.startsWith("lvt-value-")) {
|
|
468
|
-
const key = attr.name.replace("lvt-value-", "");
|
|
469
|
-
message.data[key] = this.context.parseValue(attr.value);
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
this.context.send(message);
|
|
473
|
-
}
|
|
452
|
+
const match = attr.name.match(/^lvt-el:(\w+):on:click-away$/);
|
|
453
|
+
if (!match)
|
|
454
|
+
return;
|
|
455
|
+
const method = CLICK_AWAY_METHOD_MAP[match[1].toLowerCase()];
|
|
456
|
+
if (!method)
|
|
457
|
+
return;
|
|
458
|
+
(0, reactive_attributes_1.executeAction)(element, method, attr.value);
|
|
459
|
+
});
|
|
474
460
|
});
|
|
475
461
|
};
|
|
476
462
|
document[listenerKey] = listener;
|
|
477
463
|
document.addEventListener("click", listener);
|
|
478
464
|
}
|
|
479
|
-
setupModalDelegation() {
|
|
480
|
-
const wrapperElement = this.context.getWrapperElement();
|
|
481
|
-
if (!wrapperElement)
|
|
482
|
-
return;
|
|
483
|
-
const wrapperId = wrapperElement.getAttribute("data-lvt-id");
|
|
484
|
-
const openListenerKey = `__lvt_modal_open_${wrapperId}`;
|
|
485
|
-
const existingOpenListener = document[openListenerKey];
|
|
486
|
-
if (existingOpenListener) {
|
|
487
|
-
document.removeEventListener("click", existingOpenListener);
|
|
488
|
-
}
|
|
489
|
-
const openListener = (e) => {
|
|
490
|
-
const currentWrapper = this.context.getWrapperElement();
|
|
491
|
-
if (!currentWrapper)
|
|
492
|
-
return;
|
|
493
|
-
const target = e.target?.closest("[lvt-modal-open]");
|
|
494
|
-
if (!target || !currentWrapper.contains(target))
|
|
495
|
-
return;
|
|
496
|
-
const modalId = target.getAttribute("lvt-modal-open");
|
|
497
|
-
if (!modalId)
|
|
498
|
-
return;
|
|
499
|
-
e.preventDefault();
|
|
500
|
-
this.context.openModal(modalId);
|
|
501
|
-
};
|
|
502
|
-
document[openListenerKey] = openListener;
|
|
503
|
-
document.addEventListener("click", openListener);
|
|
504
|
-
const closeListenerKey = `__lvt_modal_close_${wrapperId}`;
|
|
505
|
-
const existingCloseListener = document[closeListenerKey];
|
|
506
|
-
if (existingCloseListener) {
|
|
507
|
-
document.removeEventListener("click", existingCloseListener);
|
|
508
|
-
}
|
|
509
|
-
// Close listener is intentionally NOT scoped to wrapper (unlike openListener).
|
|
510
|
-
// Close buttons may be inside modals rendered in portals outside the wrapper.
|
|
511
|
-
// Instead, we verify the target modal exists by ID.
|
|
512
|
-
const closeListener = (e) => {
|
|
513
|
-
const target = e.target?.closest("[lvt-modal-close]");
|
|
514
|
-
if (!target)
|
|
515
|
-
return;
|
|
516
|
-
const modalId = target.getAttribute("lvt-modal-close");
|
|
517
|
-
if (!modalId)
|
|
518
|
-
return;
|
|
519
|
-
// Verify the modal exists before attempting to close
|
|
520
|
-
const modal = document.getElementById(modalId);
|
|
521
|
-
if (!modal)
|
|
522
|
-
return;
|
|
523
|
-
e.preventDefault();
|
|
524
|
-
this.context.closeModal(modalId);
|
|
525
|
-
};
|
|
526
|
-
document[closeListenerKey] = closeListener;
|
|
527
|
-
document.addEventListener("click", closeListener);
|
|
528
|
-
const backdropListenerKey = `__lvt_modal_backdrop_${wrapperId}`;
|
|
529
|
-
const existingBackdropListener = document[backdropListenerKey];
|
|
530
|
-
if (existingBackdropListener) {
|
|
531
|
-
document.removeEventListener("click", existingBackdropListener);
|
|
532
|
-
}
|
|
533
|
-
// Helper to close modal, dispatching action if data-modal-close-action is set
|
|
534
|
-
const closeModalWithAction = (modal, modalId) => {
|
|
535
|
-
const closeAction = modal.getAttribute("data-modal-close-action");
|
|
536
|
-
if (closeAction) {
|
|
537
|
-
this.context.send({ action: closeAction, data: {} });
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
this.context.closeModal(modalId);
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
const backdropListener = (e) => {
|
|
544
|
-
const target = e.target;
|
|
545
|
-
// Only trigger if clicked directly on the backdrop element itself
|
|
546
|
-
if (!target.hasAttribute("data-modal-backdrop"))
|
|
547
|
-
return;
|
|
548
|
-
const modalId = target.getAttribute("data-modal-id");
|
|
549
|
-
if (!modalId)
|
|
550
|
-
return;
|
|
551
|
-
const modal = document.getElementById(modalId);
|
|
552
|
-
if (!modal)
|
|
553
|
-
return;
|
|
554
|
-
closeModalWithAction(modal, modalId);
|
|
555
|
-
};
|
|
556
|
-
document[backdropListenerKey] = backdropListener;
|
|
557
|
-
document.addEventListener("click", backdropListener);
|
|
558
|
-
const escapeListenerKey = `__lvt_modal_escape_${wrapperId}`;
|
|
559
|
-
const existingEscapeListener = document[escapeListenerKey];
|
|
560
|
-
if (existingEscapeListener) {
|
|
561
|
-
document.removeEventListener("keydown", existingEscapeListener);
|
|
562
|
-
}
|
|
563
|
-
const escapeListener = (e) => {
|
|
564
|
-
if (e.key !== "Escape")
|
|
565
|
-
return;
|
|
566
|
-
const currentWrapper = this.context.getWrapperElement();
|
|
567
|
-
if (!currentWrapper)
|
|
568
|
-
return;
|
|
569
|
-
const openModals = currentWrapper.querySelectorAll('[role="dialog"]:not([hidden])');
|
|
570
|
-
if (openModals.length > 0) {
|
|
571
|
-
const lastModal = openModals[openModals.length - 1];
|
|
572
|
-
if (lastModal.id) {
|
|
573
|
-
closeModalWithAction(lastModal, lastModal.id);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
document[escapeListenerKey] = escapeListener;
|
|
578
|
-
document.addEventListener("keydown", escapeListener);
|
|
579
|
-
}
|
|
580
465
|
/**
|
|
581
466
|
* Sets up focus trapping for elements with lvt-focus-trap attribute.
|
|
582
467
|
* Focus is trapped within the element, cycling through focusable elements
|