@vortexm/vjt 0.1.17 → 0.1.19

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.js CHANGED
@@ -5130,7 +5130,7 @@ var ActionRuntime = class {
5130
5130
  this.getInlineActions = options.getInlineActions;
5131
5131
  this.isWidgetEnabled = options.isWidgetEnabled;
5132
5132
  }
5133
- async dispatchWidgetEvent(node, eventName, key, inputValue = null, pointer = null) {
5133
+ async dispatchWidgetEvent(node, eventName, key, inputValue = null, pointer = null, options = {}) {
5134
5134
  try {
5135
5135
  if ((eventName === "onClick" || eventName === "onUserValueChange" || eventName === "onEnter" || eventName === "onShiftEnter" || eventName === "onControlEnter") && !this.isWidgetEnabled(node, key)) {
5136
5136
  return;
@@ -5140,7 +5140,9 @@ var ActionRuntime = class {
5140
5140
  return;
5141
5141
  }
5142
5142
  await this.runActions(actions, inputValue, { currentValue: inputValue, pointer });
5143
- await this.rerenderRoot();
5143
+ if (options.rerender !== false) {
5144
+ await this.rerenderRoot();
5145
+ }
5144
5146
  } catch (error) {
5145
5147
  logRuntimeError("dispatchWidgetEvent", error, {
5146
5148
  eventName,
@@ -8088,6 +8090,7 @@ var RuntimeRenderer = class {
8088
8090
  activeScrollAnimationFrameId = null;
8089
8091
  pendingCursorReference = null;
8090
8092
  pendingCursorFrameId = null;
8093
+ scrollEventFrameIds = /* @__PURE__ */ new Map();
8091
8094
  constructor(description, options = {}) {
8092
8095
  this.description = deepClone(description);
8093
8096
  this.resourceManager = options.resourceManager ?? null;
@@ -8327,6 +8330,10 @@ var RuntimeRenderer = class {
8327
8330
  window.clearTimeout(timeoutId);
8328
8331
  }
8329
8332
  this.toastTimeoutIds.clear();
8333
+ for (const frameId of this.scrollEventFrameIds.values()) {
8334
+ window.cancelAnimationFrame(frameId);
8335
+ }
8336
+ this.scrollEventFrameIds.clear();
8330
8337
  this.voiceRuntime.dispose();
8331
8338
  };
8332
8339
  }
@@ -9516,6 +9523,7 @@ var RuntimeRenderer = class {
9516
9523
  }
9517
9524
  element.addEventListener("scroll", () => {
9518
9525
  this.syncScrollStateForElement(element, key);
9526
+ this.dispatchScrollEvent(element, node, key);
9519
9527
  }, { passive: true });
9520
9528
  }
9521
9529
  }
@@ -9965,6 +9973,92 @@ var RuntimeRenderer = class {
9965
9973
  state.isScrolledToTop = element.scrollTop <= 1;
9966
9974
  state.isScrolledToBottom = element.scrollTop >= maxScrollTop - 1;
9967
9975
  }
9976
+ dispatchScrollEvent(element, node, key) {
9977
+ if (!node.events?.onScroll?.length || typeof window === "undefined") {
9978
+ return;
9979
+ }
9980
+ const existingFrameId = this.scrollEventFrameIds.get(key);
9981
+ if (existingFrameId !== void 0) {
9982
+ return;
9983
+ }
9984
+ const frameId = window.requestAnimationFrame(() => {
9985
+ this.scrollEventFrameIds.delete(key);
9986
+ void this.actionRuntime.dispatchWidgetEvent(
9987
+ node,
9988
+ "onScroll",
9989
+ key,
9990
+ getActionInputValueForElement(element, node, this.stateByKey),
9991
+ null,
9992
+ { rerender: false }
9993
+ ).then(() => {
9994
+ this.syncSimpleDomState();
9995
+ });
9996
+ });
9997
+ this.scrollEventFrameIds.set(key, frameId);
9998
+ }
9999
+ syncSimpleDomState() {
10000
+ if (!(this.root instanceof HTMLElement)) {
10001
+ return;
10002
+ }
10003
+ for (const [key, node] of this.nodeByKey.entries()) {
10004
+ const state = this.stateByKey.get(key);
10005
+ if (!state) {
10006
+ continue;
10007
+ }
10008
+ const element = this.root.querySelector(`[data-widget-key="${CSS.escape(key)}"]`);
10009
+ if (!element) {
10010
+ continue;
10011
+ }
10012
+ switch (node.widget) {
10013
+ case "static-text": {
10014
+ const nextText = this.resolveTextValue(state.text ?? node.text, null);
10015
+ if (element.textContent !== nextText) {
10016
+ element.textContent = nextText;
10017
+ }
10018
+ break;
10019
+ }
10020
+ case "button": {
10021
+ if (element instanceof HTMLButtonElement) {
10022
+ const nextText = this.resolveTextValue(state.text ?? node.text, null);
10023
+ if (element.textContent !== nextText) {
10024
+ element.textContent = nextText;
10025
+ }
10026
+ element.disabled = !(state.enabled ?? normalizeBoolean(node.enabled, true));
10027
+ }
10028
+ break;
10029
+ }
10030
+ case "link": {
10031
+ if (element instanceof HTMLAnchorElement) {
10032
+ const nextText = this.resolveTextValue(state.text ?? node.text, null);
10033
+ if (element.textContent !== nextText) {
10034
+ element.textContent = nextText;
10035
+ }
10036
+ }
10037
+ break;
10038
+ }
10039
+ case "edit": {
10040
+ if (element instanceof HTMLInputElement) {
10041
+ const nextValue = this.resolveTextValue(state.text ?? node.text, null);
10042
+ if (element.value !== nextValue) {
10043
+ element.value = nextValue;
10044
+ }
10045
+ }
10046
+ break;
10047
+ }
10048
+ case "textarea": {
10049
+ if (element instanceof HTMLTextAreaElement) {
10050
+ const nextValue = this.resolveTextValue(state.text ?? node.text, null);
10051
+ if (element.value !== nextValue) {
10052
+ element.value = nextValue;
10053
+ }
10054
+ }
10055
+ break;
10056
+ }
10057
+ default:
10058
+ break;
10059
+ }
10060
+ }
10061
+ }
9968
10062
  toScrollableIndex(value) {
9969
10063
  if (typeof value === "number" && Number.isFinite(value)) {
9970
10064
  return Math.max(0, Math.trunc(value));
@@ -121,7 +121,9 @@ export declare class ActionRuntime {
121
121
  dispatchWidgetEvent(node: DescriptionNode, eventName: WidgetEventName, key: string, inputValue?: unknown, pointer?: {
122
122
  x: number;
123
123
  y: number;
124
- } | null): Promise<void>;
124
+ } | null, options?: {
125
+ rerender?: boolean;
126
+ }): Promise<void>;
125
127
  runActions(actions: ActionDefinition[], inputValue: unknown, context: ActionExecutionContext): Promise<unknown>;
126
128
  getInlineActionsForNode(node: DescriptionNode): ActionDefinition[] | undefined;
127
129
  private runSingleAction;
@@ -3,7 +3,7 @@ export type LayoutType = 'vertical' | 'horizontal' | 'grid';
3
3
  export type TextAlign = 'left' | 'center' | 'right';
4
4
  export type VerticalAlign = 'top' | 'center' | 'bottom';
5
5
  export type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
6
- export type WidgetEventName = 'onClick' | 'onUserValueChange' | 'onRefresh' | 'onEnter' | 'onShiftEnter' | 'onControlEnter' | 'onPaste';
6
+ export type WidgetEventName = 'onClick' | 'onUserValueChange' | 'onRefresh' | 'onEnter' | 'onShiftEnter' | 'onControlEnter' | 'onPaste' | 'onScroll';
7
7
  export type SystemEventName = 'onBeforeRender' | 'onAfterRender' | 'onBeforeNavigate' | 'onAfterNavigate' | 'onLayoutSwitchToMobile' | 'onLayoutSwitchToDesktop' | 'onSpeechDetected' | 'onRecordingStarted' | 'onRecordingStopped' | 'onRecordingError' | 'onListeningError' | 'onListeringError' | 'onPlayFinished' | 'onPlayingStopped';
8
8
  export type PrimitiveRequestType = 'int' | 'float' | 'boolean' | 'string';
9
9
  export type ClosableRuntimeResource = {
@@ -12,7 +12,7 @@ type BindingEnvironment = {
12
12
  }) => void;
13
13
  updatePointerFromEvent: (event: MouseEvent) => void;
14
14
  updateOwningListElementDescriptor: (element: HTMLElement, mutate: (descriptor: DescriptionNode) => void) => void;
15
- dispatchWidgetEvent: (node: DescriptionNode, eventName: 'onClick' | 'onUserValueChange' | 'onEnter' | 'onShiftEnter' | 'onControlEnter' | 'onPaste', key: string, inputValue?: unknown, pointer?: {
15
+ dispatchWidgetEvent: (node: DescriptionNode, eventName: 'onClick' | 'onUserValueChange' | 'onEnter' | 'onShiftEnter' | 'onControlEnter' | 'onPaste' | 'onScroll', key: string, inputValue?: unknown, pointer?: {
16
16
  x: number;
17
17
  y: number;
18
18
  } | null) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vortexm/vjt",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",