@jay-framework/stack-client-runtime 0.12.0 → 0.13.0
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/index.cjs +71 -21
- package/dist/index.d.ts +4 -2
- package/dist/index.js +72 -22
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -89,8 +89,9 @@ function makeSignals$1(obj) {
|
|
|
89
89
|
function makeHeadlessInstanceComponent(preRender, interactiveConstructor, coordinateKey, pluginContexts = []) {
|
|
90
90
|
const wrappedConstructor = (props, refs, ...pluginResolvedContexts) => {
|
|
91
91
|
const instanceData = runtime.useContext(HEADLESS_INSTANCES);
|
|
92
|
-
const
|
|
93
|
-
const
|
|
92
|
+
const resolvedKey = typeof coordinateKey === "function" ? coordinateKey(runtime.currentConstructionContext()?.dataIds ?? []) : coordinateKey;
|
|
93
|
+
const fastVS = instanceData?.viewStates?.[resolvedKey];
|
|
94
|
+
const cf = instanceData?.carryForwards?.[resolvedKey] || {};
|
|
94
95
|
const signalVS = fastVS ? makeSignals$1(fastVS) : void 0;
|
|
95
96
|
return interactiveConstructor(props, refs, signalVS, cf, ...pluginResolvedContexts);
|
|
96
97
|
};
|
|
@@ -357,14 +358,13 @@ function collectInteractionsRecursive(refs, interactions) {
|
|
|
357
358
|
continue;
|
|
358
359
|
if (refImpl.elements && refImpl.elements instanceof Set) {
|
|
359
360
|
for (const elem of refImpl.elements) {
|
|
360
|
-
if (elem.element) {
|
|
361
|
+
if (elem.element && !isDisabled(elem.element)) {
|
|
361
362
|
interactions.push({
|
|
362
363
|
refName,
|
|
363
364
|
coordinate: elem.coordinate || [refName],
|
|
364
365
|
element: elem.element,
|
|
365
|
-
elementType: getElementType(elem.element),
|
|
366
366
|
supportedEvents: getSupportedEvents(elem.element),
|
|
367
|
-
|
|
367
|
+
description: elem.description
|
|
368
368
|
});
|
|
369
369
|
}
|
|
370
370
|
}
|
|
@@ -383,8 +383,12 @@ function isNestedRefsObject(obj) {
|
|
|
383
383
|
return false;
|
|
384
384
|
return true;
|
|
385
385
|
}
|
|
386
|
-
function
|
|
387
|
-
|
|
386
|
+
function isDisabled(element) {
|
|
387
|
+
if ("disabled" in element && element.disabled) {
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
const fieldset = element.closest?.("fieldset:disabled");
|
|
391
|
+
return !!fieldset;
|
|
388
392
|
}
|
|
389
393
|
function getSupportedEvents(element) {
|
|
390
394
|
const base = ["click", "focus", "blur"];
|
|
@@ -408,11 +412,45 @@ function getSupportedEvents(element) {
|
|
|
408
412
|
}
|
|
409
413
|
return base;
|
|
410
414
|
}
|
|
415
|
+
function groupInteractions(raw) {
|
|
416
|
+
const byRef = /* @__PURE__ */ new Map();
|
|
417
|
+
for (const item of raw) {
|
|
418
|
+
let group = byRef.get(item.refName);
|
|
419
|
+
if (!group) {
|
|
420
|
+
group = [];
|
|
421
|
+
byRef.set(item.refName, group);
|
|
422
|
+
}
|
|
423
|
+
group.push(item);
|
|
424
|
+
}
|
|
425
|
+
return Array.from(byRef.entries()).map(([refName, items]) => ({
|
|
426
|
+
refName,
|
|
427
|
+
description: items[0].description,
|
|
428
|
+
items: items.map(toInstance)
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
function toInstance(raw) {
|
|
432
|
+
return {
|
|
433
|
+
coordinate: raw.coordinate,
|
|
434
|
+
element: raw.element,
|
|
435
|
+
events: relevantEvents(raw)
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function relevantEvents(raw) {
|
|
439
|
+
const el = raw.element;
|
|
440
|
+
if (el instanceof HTMLButtonElement || el instanceof HTMLAnchorElement) {
|
|
441
|
+
return ["click"];
|
|
442
|
+
}
|
|
443
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
444
|
+
return raw.supportedEvents.filter((e) => e === "input" || e === "change");
|
|
445
|
+
}
|
|
446
|
+
return raw.supportedEvents;
|
|
447
|
+
}
|
|
411
448
|
const VIEW_STATE_CHANGE = "viewStateChange";
|
|
412
449
|
class AutomationAgent {
|
|
413
450
|
constructor(component2, options) {
|
|
414
451
|
__publicField2(this, "stateListeners", /* @__PURE__ */ new Set());
|
|
415
|
-
__publicField2(this, "
|
|
452
|
+
__publicField2(this, "cachedRaw", null);
|
|
453
|
+
__publicField2(this, "cachedGrouped", null);
|
|
416
454
|
__publicField2(this, "viewStateHandler", null);
|
|
417
455
|
__publicField2(this, "mergedViewState");
|
|
418
456
|
__publicField2(this, "initialSlowViewState");
|
|
@@ -431,7 +469,8 @@ class AutomationAgent {
|
|
|
431
469
|
}
|
|
432
470
|
subscribeToUpdates() {
|
|
433
471
|
this.viewStateHandler = () => {
|
|
434
|
-
this.
|
|
472
|
+
this.cachedRaw = null;
|
|
473
|
+
this.cachedGrouped = null;
|
|
435
474
|
if (this.initialSlowViewState && this.trackByMap) {
|
|
436
475
|
this.mergedViewState = deepMergeViewStates(
|
|
437
476
|
this.initialSlowViewState,
|
|
@@ -449,33 +488,43 @@ class AutomationAgent {
|
|
|
449
488
|
const state = this.getPageState();
|
|
450
489
|
this.stateListeners.forEach((callback) => callback(state));
|
|
451
490
|
}
|
|
452
|
-
|
|
453
|
-
if (!this.
|
|
454
|
-
|
|
491
|
+
getGrouped() {
|
|
492
|
+
if (!this.cachedGrouped) {
|
|
493
|
+
if (!this.cachedRaw) {
|
|
494
|
+
this.cachedRaw = collectInteractions(this.component.element?.refs);
|
|
495
|
+
}
|
|
496
|
+
this.cachedGrouped = groupInteractions(this.cachedRaw);
|
|
455
497
|
}
|
|
498
|
+
return this.cachedGrouped;
|
|
499
|
+
}
|
|
500
|
+
getPageState() {
|
|
456
501
|
return {
|
|
457
502
|
// Use merged state if available (slow+fast), otherwise component's viewState
|
|
458
503
|
viewState: this.mergedViewState || this.component.viewState,
|
|
459
|
-
interactions: this.
|
|
504
|
+
interactions: this.getGrouped(),
|
|
460
505
|
customEvents: this.getCustomEvents()
|
|
461
506
|
};
|
|
462
507
|
}
|
|
463
508
|
triggerEvent(eventType, coordinate, eventData) {
|
|
464
|
-
const
|
|
465
|
-
if (!
|
|
509
|
+
const instance = this.getInteraction(coordinate);
|
|
510
|
+
if (!instance) {
|
|
466
511
|
throw new Error(`No element found at coordinate: ${coordinate.join("/")}`);
|
|
467
512
|
}
|
|
468
513
|
const event = new Event(eventType, { bubbles: true });
|
|
469
514
|
if (eventData) {
|
|
470
515
|
Object.assign(event, eventData);
|
|
471
516
|
}
|
|
472
|
-
|
|
517
|
+
instance.element.dispatchEvent(event);
|
|
473
518
|
}
|
|
474
519
|
getInteraction(coordinate) {
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
520
|
+
for (const group of this.getGrouped()) {
|
|
521
|
+
for (const instance of group.items) {
|
|
522
|
+
if (instance.coordinate.length === coordinate.length && instance.coordinate.every((c, idx) => c === coordinate[idx])) {
|
|
523
|
+
return instance;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return void 0;
|
|
479
528
|
}
|
|
480
529
|
onStateChange(callback) {
|
|
481
530
|
this.stateListeners.add(callback);
|
|
@@ -508,7 +557,8 @@ class AutomationAgent {
|
|
|
508
557
|
this.viewStateHandler = null;
|
|
509
558
|
}
|
|
510
559
|
this.stateListeners.clear();
|
|
511
|
-
this.
|
|
560
|
+
this.cachedRaw = null;
|
|
561
|
+
this.cachedGrouped = null;
|
|
512
562
|
}
|
|
513
563
|
}
|
|
514
564
|
function wrapWithAutomation(component2, options) {
|
package/dist/index.d.ts
CHANGED
|
@@ -53,10 +53,12 @@ declare const HEADLESS_INSTANCES: ContextMarker<HeadlessInstancesData>;
|
|
|
53
53
|
*
|
|
54
54
|
* @param preRender - The inline template's render function
|
|
55
55
|
* @param interactiveConstructor - The plugin's interactive constructor
|
|
56
|
-
* @param coordinateKey -
|
|
56
|
+
* @param coordinateKey - Static coordinate key (e.g., "product-card:0") or a
|
|
57
|
+
* factory function for forEach instances that receives the current dataIds
|
|
58
|
+
* (accumulated trackBy values from ancestor forEach loops) and returns the key.
|
|
57
59
|
* @param pluginContexts - Additional context markers from the plugin (if any)
|
|
58
60
|
*/
|
|
59
|
-
declare function makeHeadlessInstanceComponent<PropsT extends object, ViewState extends object, Refs extends object, JayElementT extends JayElement<ViewState, Refs>, CompCore extends JayComponentCore<PropsT, ViewState>>(preRender: PreRenderElement<ViewState, Refs, JayElementT>, interactiveConstructor: ComponentConstructor<PropsT, Refs, ViewState, any, CompCore>, coordinateKey: string, pluginContexts?: ContextMarkers<any>): any;
|
|
61
|
+
declare function makeHeadlessInstanceComponent<PropsT extends object, ViewState extends object, Refs extends object, JayElementT extends JayElement<ViewState, Refs>, CompCore extends JayComponentCore<PropsT, ViewState>>(preRender: PreRenderElement<ViewState, Refs, JayElementT>, interactiveConstructor: ComponentConstructor<PropsT, Refs, ViewState, any, CompCore>, coordinateKey: string | ((dataIds: string[]) => string), pluginContexts?: ContextMarkers<any>): any;
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
64
|
* Client-side action caller for Jay Stack.
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
7
|
import { makeJayComponent, createSignal, COMPONENT_CONTEXT, materializeViewState } from "@jay-framework/component";
|
|
8
|
-
import { createJayContext, useContext } from "@jay-framework/runtime";
|
|
8
|
+
import { createJayContext, useContext, currentConstructionContext } from "@jay-framework/runtime";
|
|
9
9
|
function deepMergeViewStates$1(base, overlay, trackByMap, path = "") {
|
|
10
10
|
if (!base && !overlay)
|
|
11
11
|
return {};
|
|
@@ -87,8 +87,9 @@ function makeSignals$1(obj) {
|
|
|
87
87
|
function makeHeadlessInstanceComponent(preRender, interactiveConstructor, coordinateKey, pluginContexts = []) {
|
|
88
88
|
const wrappedConstructor = (props, refs, ...pluginResolvedContexts) => {
|
|
89
89
|
const instanceData = useContext(HEADLESS_INSTANCES);
|
|
90
|
-
const
|
|
91
|
-
const
|
|
90
|
+
const resolvedKey = typeof coordinateKey === "function" ? coordinateKey(currentConstructionContext()?.dataIds ?? []) : coordinateKey;
|
|
91
|
+
const fastVS = instanceData?.viewStates?.[resolvedKey];
|
|
92
|
+
const cf = instanceData?.carryForwards?.[resolvedKey] || {};
|
|
92
93
|
const signalVS = fastVS ? makeSignals$1(fastVS) : void 0;
|
|
93
94
|
return interactiveConstructor(props, refs, signalVS, cf, ...pluginResolvedContexts);
|
|
94
95
|
};
|
|
@@ -355,14 +356,13 @@ function collectInteractionsRecursive(refs, interactions) {
|
|
|
355
356
|
continue;
|
|
356
357
|
if (refImpl.elements && refImpl.elements instanceof Set) {
|
|
357
358
|
for (const elem of refImpl.elements) {
|
|
358
|
-
if (elem.element) {
|
|
359
|
+
if (elem.element && !isDisabled(elem.element)) {
|
|
359
360
|
interactions.push({
|
|
360
361
|
refName,
|
|
361
362
|
coordinate: elem.coordinate || [refName],
|
|
362
363
|
element: elem.element,
|
|
363
|
-
elementType: getElementType(elem.element),
|
|
364
364
|
supportedEvents: getSupportedEvents(elem.element),
|
|
365
|
-
|
|
365
|
+
description: elem.description
|
|
366
366
|
});
|
|
367
367
|
}
|
|
368
368
|
}
|
|
@@ -381,8 +381,12 @@ function isNestedRefsObject(obj) {
|
|
|
381
381
|
return false;
|
|
382
382
|
return true;
|
|
383
383
|
}
|
|
384
|
-
function
|
|
385
|
-
|
|
384
|
+
function isDisabled(element) {
|
|
385
|
+
if ("disabled" in element && element.disabled) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
const fieldset = element.closest?.("fieldset:disabled");
|
|
389
|
+
return !!fieldset;
|
|
386
390
|
}
|
|
387
391
|
function getSupportedEvents(element) {
|
|
388
392
|
const base = ["click", "focus", "blur"];
|
|
@@ -406,11 +410,45 @@ function getSupportedEvents(element) {
|
|
|
406
410
|
}
|
|
407
411
|
return base;
|
|
408
412
|
}
|
|
413
|
+
function groupInteractions(raw) {
|
|
414
|
+
const byRef = /* @__PURE__ */ new Map();
|
|
415
|
+
for (const item of raw) {
|
|
416
|
+
let group = byRef.get(item.refName);
|
|
417
|
+
if (!group) {
|
|
418
|
+
group = [];
|
|
419
|
+
byRef.set(item.refName, group);
|
|
420
|
+
}
|
|
421
|
+
group.push(item);
|
|
422
|
+
}
|
|
423
|
+
return Array.from(byRef.entries()).map(([refName, items]) => ({
|
|
424
|
+
refName,
|
|
425
|
+
description: items[0].description,
|
|
426
|
+
items: items.map(toInstance)
|
|
427
|
+
}));
|
|
428
|
+
}
|
|
429
|
+
function toInstance(raw) {
|
|
430
|
+
return {
|
|
431
|
+
coordinate: raw.coordinate,
|
|
432
|
+
element: raw.element,
|
|
433
|
+
events: relevantEvents(raw)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function relevantEvents(raw) {
|
|
437
|
+
const el = raw.element;
|
|
438
|
+
if (el instanceof HTMLButtonElement || el instanceof HTMLAnchorElement) {
|
|
439
|
+
return ["click"];
|
|
440
|
+
}
|
|
441
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
442
|
+
return raw.supportedEvents.filter((e) => e === "input" || e === "change");
|
|
443
|
+
}
|
|
444
|
+
return raw.supportedEvents;
|
|
445
|
+
}
|
|
409
446
|
const VIEW_STATE_CHANGE = "viewStateChange";
|
|
410
447
|
class AutomationAgent {
|
|
411
448
|
constructor(component, options) {
|
|
412
449
|
__publicField2(this, "stateListeners", /* @__PURE__ */ new Set());
|
|
413
|
-
__publicField2(this, "
|
|
450
|
+
__publicField2(this, "cachedRaw", null);
|
|
451
|
+
__publicField2(this, "cachedGrouped", null);
|
|
414
452
|
__publicField2(this, "viewStateHandler", null);
|
|
415
453
|
__publicField2(this, "mergedViewState");
|
|
416
454
|
__publicField2(this, "initialSlowViewState");
|
|
@@ -429,7 +467,8 @@ class AutomationAgent {
|
|
|
429
467
|
}
|
|
430
468
|
subscribeToUpdates() {
|
|
431
469
|
this.viewStateHandler = () => {
|
|
432
|
-
this.
|
|
470
|
+
this.cachedRaw = null;
|
|
471
|
+
this.cachedGrouped = null;
|
|
433
472
|
if (this.initialSlowViewState && this.trackByMap) {
|
|
434
473
|
this.mergedViewState = deepMergeViewStates(
|
|
435
474
|
this.initialSlowViewState,
|
|
@@ -447,33 +486,43 @@ class AutomationAgent {
|
|
|
447
486
|
const state = this.getPageState();
|
|
448
487
|
this.stateListeners.forEach((callback) => callback(state));
|
|
449
488
|
}
|
|
450
|
-
|
|
451
|
-
if (!this.
|
|
452
|
-
|
|
489
|
+
getGrouped() {
|
|
490
|
+
if (!this.cachedGrouped) {
|
|
491
|
+
if (!this.cachedRaw) {
|
|
492
|
+
this.cachedRaw = collectInteractions(this.component.element?.refs);
|
|
493
|
+
}
|
|
494
|
+
this.cachedGrouped = groupInteractions(this.cachedRaw);
|
|
453
495
|
}
|
|
496
|
+
return this.cachedGrouped;
|
|
497
|
+
}
|
|
498
|
+
getPageState() {
|
|
454
499
|
return {
|
|
455
500
|
// Use merged state if available (slow+fast), otherwise component's viewState
|
|
456
501
|
viewState: this.mergedViewState || this.component.viewState,
|
|
457
|
-
interactions: this.
|
|
502
|
+
interactions: this.getGrouped(),
|
|
458
503
|
customEvents: this.getCustomEvents()
|
|
459
504
|
};
|
|
460
505
|
}
|
|
461
506
|
triggerEvent(eventType, coordinate, eventData) {
|
|
462
|
-
const
|
|
463
|
-
if (!
|
|
507
|
+
const instance = this.getInteraction(coordinate);
|
|
508
|
+
if (!instance) {
|
|
464
509
|
throw new Error(`No element found at coordinate: ${coordinate.join("/")}`);
|
|
465
510
|
}
|
|
466
511
|
const event = new Event(eventType, { bubbles: true });
|
|
467
512
|
if (eventData) {
|
|
468
513
|
Object.assign(event, eventData);
|
|
469
514
|
}
|
|
470
|
-
|
|
515
|
+
instance.element.dispatchEvent(event);
|
|
471
516
|
}
|
|
472
517
|
getInteraction(coordinate) {
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
518
|
+
for (const group of this.getGrouped()) {
|
|
519
|
+
for (const instance of group.items) {
|
|
520
|
+
if (instance.coordinate.length === coordinate.length && instance.coordinate.every((c, idx) => c === coordinate[idx])) {
|
|
521
|
+
return instance;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return void 0;
|
|
477
526
|
}
|
|
478
527
|
onStateChange(callback) {
|
|
479
528
|
this.stateListeners.add(callback);
|
|
@@ -506,7 +555,8 @@ class AutomationAgent {
|
|
|
506
555
|
this.viewStateHandler = null;
|
|
507
556
|
}
|
|
508
557
|
this.stateListeners.clear();
|
|
509
|
-
this.
|
|
558
|
+
this.cachedRaw = null;
|
|
559
|
+
this.cachedGrouped = null;
|
|
510
560
|
}
|
|
511
561
|
}
|
|
512
562
|
function wrapWithAutomation(component, options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/stack-client-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"test:watch": "vitest"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@jay-framework/component": "^0.
|
|
31
|
-
"@jay-framework/fullstack-component": "^0.
|
|
32
|
-
"@jay-framework/runtime": "^0.
|
|
33
|
-
"@jay-framework/runtime-automation": "^0.
|
|
34
|
-
"@jay-framework/view-state-merge": "^0.
|
|
30
|
+
"@jay-framework/component": "^0.13.0",
|
|
31
|
+
"@jay-framework/fullstack-component": "^0.13.0",
|
|
32
|
+
"@jay-framework/runtime": "^0.13.0",
|
|
33
|
+
"@jay-framework/runtime-automation": "^0.13.0",
|
|
34
|
+
"@jay-framework/view-state-merge": "^0.13.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@jay-framework/dev-environment": "^0.
|
|
38
|
-
"@jay-framework/jay-cli": "^0.
|
|
37
|
+
"@jay-framework/dev-environment": "^0.13.0",
|
|
38
|
+
"@jay-framework/jay-cli": "^0.13.0",
|
|
39
39
|
"@types/express": "^5.0.2",
|
|
40
40
|
"@types/node": "^22.15.21",
|
|
41
41
|
"nodemon": "^3.0.3",
|