From 98b9346b1a897c2c731bb4b450ce9a3aa2162e1c Mon Sep 17 00:00:00 2001 From: Seva Zaikov Date: Sun, 9 Jun 2024 00:16:19 -0700 Subject: [PATCH] allow dynamic adding and removing event listeners (#52) --- integration-tests/assign-attributes.test.ts | 93 +- .../create-state/create-state.test.ts | 2 +- .../create-state/track-value.test.ts | 8 +- src/create-element/assign-attributes.ts | 56 +- src/hooks/create-state.ts | 29 +- src/jsx.d.ts | 906 ++++++++++++++---- src/types.d.ts | 4 +- 7 files changed, 881 insertions(+), 217 deletions(-) diff --git a/integration-tests/assign-attributes.test.ts b/integration-tests/assign-attributes.test.ts index 58ab68c..9bd3fc1 100644 --- a/integration-tests/assign-attributes.test.ts +++ b/integration-tests/assign-attributes.test.ts @@ -43,7 +43,8 @@ describe("createState", () => { value: nameState.useAttribute((name) => name), onFocus: focusFn, onBlur: blurFn, - onInput: (e) => nameState.setValue(() => e.target.value), + onInput: (e) => + nameState.setValue((e.target as HTMLInputElement).value), }), nameState.useValue((value) => createElement("div", { @@ -101,7 +102,8 @@ describe("createState", () => { value: nameState.useAttribute(), onFocus: focusFn, onBlur: blurFn, - onInput: (e) => nameState.setValue(e.target.value), + onInput: (e) => + nameState.setValue((e.target as HTMLInputElement).value), }), nameState.useValue((value) => createElement("div", { @@ -216,4 +218,91 @@ describe("createState", () => { expect(testBtn.getAttribute("disabled")).toBe(null); expect((testBtn as HTMLButtonElement).disabled).toBe(false); }); + + it("allows to assign and remove event listeners dynamically", async () => { + const user = userEvent.setup(); + const state = createState(0); + const spyFn = jest.fn(); + function App() { + return createElement("div", { + children: [ + createElement("button", { + "data-testid": "button", + onClick: state.useAttribute((value) => + value !== 0 && value < 4 + ? () => { + spyFn(); + state.setValue((currentValue) => currentValue + 1); + } + : undefined + ), + }), + ], + }); + } + + cleanup = attachComponent({ + htmlElement: document.body, + component: createElement(App), + }); + + const btn = screen.getByTestId("button"); + + await user.click(btn); + await user.click(btn); + + state.setValue(1); + + await user.click(btn); + await user.click(btn); + await user.click(btn); + await user.click(btn); + await user.click(btn); + + expect(spyFn).toHaveBeenCalledTimes(3); + expect(state.getValue()).toBe(4); + }); + + it("allows to assign and remove event listeners dynamically passing the same callback", async () => { + const user = userEvent.setup(); + const state = createState(0); + const spyFn = jest.fn(); + function App() { + const handler = () => { + spyFn(); + state.setValue((currentValue) => currentValue + 1); + }; + return createElement("div", { + children: [ + createElement("button", { + "data-testid": "button", + onClick: state.useAttribute((value) => + value !== 0 && value < 4 ? handler : undefined + ), + }), + ], + }); + } + + cleanup = attachComponent({ + htmlElement: document.body, + component: createElement(App), + }); + + const btn = screen.getByTestId("button"); + + await user.click(btn); + await user.click(btn); + + state.setValue(1); + + await user.click(btn); + await user.click(btn); + await user.click(btn); + await user.click(btn); + await user.click(btn); + + expect(spyFn).toHaveBeenCalledTimes(3); + expect(state.getValue()).toBe(4); + }); }); diff --git a/integration-tests/create-state/create-state.test.ts b/integration-tests/create-state/create-state.test.ts index 1d905e7..100abe8 100644 --- a/integration-tests/create-state/create-state.test.ts +++ b/integration-tests/create-state/create-state.test.ts @@ -64,7 +64,7 @@ describe("createState", () => { test("supports direct state updates", async () => { const user = userEvent.setup(); function StateComponent() { - const nameState = createState(0); + const nameState = createState(""); return createElement("div", { children: [ createElement("input", { diff --git a/integration-tests/create-state/track-value.test.ts b/integration-tests/create-state/track-value.test.ts index eac338d..1983178 100644 --- a/integration-tests/create-state/track-value.test.ts +++ b/integration-tests/create-state/track-value.test.ts @@ -178,7 +178,7 @@ describe("createState", () => { onInput: (e) => userState.setValue((currentUser) => ({ ...currentUser, - name: e.target.value, + name: (e.target as HTMLInputElement).value, })), }), createElement("input", { @@ -190,7 +190,7 @@ describe("createState", () => { onInput: (e) => userState.setValue((currentUser) => ({ ...currentUser, - email: e.target.value, + email: (e.target as HTMLInputElement).value, })), }), ], @@ -244,7 +244,7 @@ describe("createState", () => { onInput: (e) => userState.setValue((currentUser) => ({ ...currentUser, - name: e.target.value, + name: (e.target as HTMLInputElement).value, })), }), createElement("input", { @@ -256,7 +256,7 @@ describe("createState", () => { onInput: (e) => userState.setValue((currentUser) => ({ ...currentUser, - email: e.target.value, + email: (e.target as HTMLInputElement).value, })), }), ], diff --git a/src/create-element/assign-attributes.ts b/src/create-element/assign-attributes.ts index 9e2bf58..1fd9070 100644 --- a/src/create-element/assign-attributes.ts +++ b/src/create-element/assign-attributes.ts @@ -13,32 +13,42 @@ function assignAttributes({ const isFunction = typeof value === "function"; if (isFunction && value.velesAttribute === true) { const attributeValue = value(htmlElement, key, velesNode); - if (typeof attributeValue === "boolean") { - // according to the spec, boolean values should just get either an empty string - // or duplicated key. I don't see a reason to duplicate the key. - // If the value is `false`, no need to set it, the correct behaviour is to remove it. - if (value) htmlElement.setAttribute(key, ""); - } else { - htmlElement.setAttribute(key, attributeValue); - } - } else if ( - // basically, any form of `on` handlers, like `onClick`, `onCopy`, etc - isFunction && - key.startsWith("on") - ) { - // TODO: think if this is robust enough - htmlElement.addEventListener( - key[2].toLocaleLowerCase() + key.slice(3), - value - ); + assignAttribute({ key, value: attributeValue, htmlElement }); } else { - if (typeof value === "boolean") { - if (value) htmlElement.setAttribute(key, ""); - } else { - htmlElement.setAttribute(key, value); - } + assignAttribute({ key, value, htmlElement }); } }); } +function assignAttribute({ + key, + value, + htmlElement, +}: { + key: string; + value: any; + htmlElement: HTMLElement; +}) { + if ( + // basically, any form of `on` handlers, like `onClick`, `onCopy`, etc + typeof value === "function" && + key.startsWith("on") + ) { + // TODO: think if this is robust enough + htmlElement.addEventListener( + key[2].toLocaleLowerCase() + key.slice(3), + value + ); + } else { + if (typeof value === "boolean") { + // according to the spec, boolean values should just get either an empty string + // or duplicated key. I don't see a reason to duplicate the key. + // If the value is `false`, no need to set it, the correct behaviour is to remove it. + if (value) htmlElement.setAttribute(key, ""); + } else { + htmlElement.setAttribute(key, value); + } + } +} + export { assignAttributes }; diff --git a/src/hooks/create-state.ts b/src/hooks/create-state.ts index 5392f29..2ed993f 100644 --- a/src/hooks/create-state.ts +++ b/src/hooks/create-state.ts @@ -118,6 +118,7 @@ function createState( cb?: Function; htmlElement: HTMLElement; attributeName: string; + attributeValue: any; }[] = []; let trackingIterators: TrackingParams[] = []; @@ -299,7 +300,8 @@ function createState( // attributes // the HTML node does not change, so we don't need to modify the array - trackingAttributes.forEach(({ cb, htmlElement, attributeName }) => { + trackingAttributes.forEach((element) => { + const { cb, htmlElement, attributeName, attributeValue } = element; const newAttributeValue = cb ? cb(value) : value; if (typeof newAttributeValue === "boolean") { @@ -308,6 +310,24 @@ function createState( } else { htmlElement.removeAttribute(attributeName); } + } else if (attributeName.startsWith("on")) { + // if the value is the same, it is either not set + // or we received the same event handler + // either way, no need to do anything + if (attributeValue === newAttributeValue) { + return; + } + + const eventName = + attributeName[2].toLocaleLowerCase() + attributeName.slice(3); + if (attributeValue) { + htmlElement.removeEventListener(eventName, attributeValue); + } + if (newAttributeValue && typeof newAttributeValue === "function") { + htmlElement.addEventListener(eventName, newAttributeValue); + } + // not the best approach, but it should work as expected + element.attributeValue = newAttributeValue; } else { htmlElement.setAttribute(attributeName, newAttributeValue); } @@ -776,7 +796,12 @@ function createState( // read that array on `_triggerUpdates` // and change inline // we need to save the HTML element and the name of the attribute - const trackingElement = { cb, htmlElement, attributeName }; + const trackingElement = { + cb, + htmlElement, + attributeName, + attributeValue, + }; trackingAttributes.push(trackingElement); node._privateMethods._addUnmountHandler(() => { diff --git a/src/jsx.d.ts b/src/jsx.d.ts index 2b1d10b..e6b5331 100644 --- a/src/jsx.d.ts +++ b/src/jsx.d.ts @@ -1626,224 +1626,762 @@ export namespace JSX { export interface DOMAttributes extends VelesDOMAttributes { // Image Events - onLoad?: GenericEventHandler | undefined; - onLoadCapture?: GenericEventHandler | undefined; - onError?: GenericEventHandler | undefined; - onErrorCapture?: GenericEventHandler | undefined; + onLoad?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onError?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onErrorCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // Clipboard Events - onCopy?: ClipboardEventHandler | undefined; - onCopyCapture?: ClipboardEventHandler | undefined; - onCut?: ClipboardEventHandler | undefined; - onCutCapture?: ClipboardEventHandler | undefined; - onPaste?: ClipboardEventHandler | undefined; - onPasteCapture?: ClipboardEventHandler | undefined; + onCopy?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; + onCopyCapture?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; + onCut?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; + onCutCapture?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; + onPaste?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; + onPasteCapture?: + | ClipboardEventHandler + | undefined + | AttributeHelper | undefined>; // Composition Events - onCompositionEnd?: CompositionEventHandler | undefined; - onCompositionEndCapture?: CompositionEventHandler | undefined; - onCompositionStart?: CompositionEventHandler | undefined; - onCompositionStartCapture?: CompositionEventHandler | undefined; - onCompositionUpdate?: CompositionEventHandler | undefined; - onCompositionUpdateCapture?: CompositionEventHandler | undefined; + onCompositionEnd?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; + onCompositionEndCapture?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; + onCompositionStart?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; + onCompositionStartCapture?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; + onCompositionUpdate?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; + onCompositionUpdateCapture?: + | CompositionEventHandler + | undefined + | AttributeHelper | undefined>; // Details Events - onToggle?: GenericEventHandler | undefined; + onToggle?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // Dialog Events - onClose?: GenericEventHandler | undefined; - onCancel?: GenericEventHandler | undefined; + onClose?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onCancel?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // Focus Events - onFocus?: FocusEventHandler | undefined; - onFocusCapture?: FocusEventHandler | undefined; - onFocusIn?: FocusEventHandler | undefined; - onFocusInCapture?: FocusEventHandler | undefined; - onFocusOut?: FocusEventHandler | undefined; - onFocusOutCapture?: FocusEventHandler | undefined; - onBlur?: FocusEventHandler | undefined; - onBlurCapture?: FocusEventHandler | undefined; + onFocus?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onFocusCapture?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onFocusIn?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onFocusInCapture?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onFocusOut?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onFocusOutCapture?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onBlur?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; + onBlurCapture?: + | FocusEventHandler + | undefined + | AttributeHelper | undefined>; // Form Events - onChange?: GenericEventHandler | undefined; - onChangeCapture?: GenericEventHandler | undefined; - onInput?: InputEventHandler | undefined; - onInputCapture?: InputEventHandler | undefined; - onBeforeInput?: InputEventHandler | undefined; - onBeforeInputCapture?: InputEventHandler | undefined; - onSearch?: GenericEventHandler | undefined; - onSearchCapture?: GenericEventHandler | undefined; - onSubmit?: SubmitEventHandler | undefined; - onSubmitCapture?: SubmitEventHandler | undefined; - onInvalid?: GenericEventHandler | undefined; - onInvalidCapture?: GenericEventHandler | undefined; - onReset?: GenericEventHandler | undefined; - onResetCapture?: GenericEventHandler | undefined; - onFormData?: GenericEventHandler | undefined; - onFormDataCapture?: GenericEventHandler | undefined; + onChange?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onChangeCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onInput?: + | InputEventHandler + | undefined + | AttributeHelper | undefined>; + onInputCapture?: + | InputEventHandler + | undefined + | AttributeHelper | undefined>; + onBeforeInput?: + | InputEventHandler + | undefined + | AttributeHelper | undefined>; + onBeforeInputCapture?: + | InputEventHandler + | undefined + | AttributeHelper | undefined>; + onSearch?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSearchCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSubmit?: + | SubmitEventHandler + | undefined + | AttributeHelper | undefined>; + onSubmitCapture?: + | SubmitEventHandler + | undefined + | AttributeHelper | undefined>; + onInvalid?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onInvalidCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onReset?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onResetCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onFormData?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onFormDataCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // Keyboard Events - onKeyDown?: KeyboardEventHandler | undefined; - onKeyDownCapture?: KeyboardEventHandler | undefined; - onKeyPress?: KeyboardEventHandler | undefined; - onKeyPressCapture?: KeyboardEventHandler | undefined; - onKeyUp?: KeyboardEventHandler | undefined; - onKeyUpCapture?: KeyboardEventHandler | undefined; + onKeyDown?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; + onKeyDownCapture?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; + onKeyPress?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; + onKeyPressCapture?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; + onKeyUp?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; + onKeyUpCapture?: + | KeyboardEventHandler + | undefined + | AttributeHelper | undefined>; // Media Events - onAbort?: GenericEventHandler | undefined; - onAbortCapture?: GenericEventHandler | undefined; - onCanPlay?: GenericEventHandler | undefined; - onCanPlayCapture?: GenericEventHandler | undefined; - onCanPlayThrough?: GenericEventHandler | undefined; - onCanPlayThroughCapture?: GenericEventHandler | undefined; - onDurationChange?: GenericEventHandler | undefined; - onDurationChangeCapture?: GenericEventHandler | undefined; - onEmptied?: GenericEventHandler | undefined; - onEmptiedCapture?: GenericEventHandler | undefined; - onEncrypted?: GenericEventHandler | undefined; - onEncryptedCapture?: GenericEventHandler | undefined; - onEnded?: GenericEventHandler | undefined; - onEndedCapture?: GenericEventHandler | undefined; - onLoadedData?: GenericEventHandler | undefined; - onLoadedDataCapture?: GenericEventHandler | undefined; - onLoadedMetadata?: GenericEventHandler | undefined; - onLoadedMetadataCapture?: GenericEventHandler | undefined; - onLoadStart?: GenericEventHandler | undefined; - onLoadStartCapture?: GenericEventHandler | undefined; - onPause?: GenericEventHandler | undefined; - onPauseCapture?: GenericEventHandler | undefined; - onPlay?: GenericEventHandler | undefined; - onPlayCapture?: GenericEventHandler | undefined; - onPlaying?: GenericEventHandler | undefined; - onPlayingCapture?: GenericEventHandler | undefined; - onProgress?: GenericEventHandler | undefined; - onProgressCapture?: GenericEventHandler | undefined; - onRateChange?: GenericEventHandler | undefined; - onRateChangeCapture?: GenericEventHandler | undefined; - onSeeked?: GenericEventHandler | undefined; - onSeekedCapture?: GenericEventHandler | undefined; - onSeeking?: GenericEventHandler | undefined; - onSeekingCapture?: GenericEventHandler | undefined; - onStalled?: GenericEventHandler | undefined; - onStalledCapture?: GenericEventHandler | undefined; - onSuspend?: GenericEventHandler | undefined; - onSuspendCapture?: GenericEventHandler | undefined; - onTimeUpdate?: GenericEventHandler | undefined; - onTimeUpdateCapture?: GenericEventHandler | undefined; - onVolumeChange?: GenericEventHandler | undefined; - onVolumeChangeCapture?: GenericEventHandler | undefined; - onWaiting?: GenericEventHandler | undefined; - onWaitingCapture?: GenericEventHandler | undefined; + onAbort?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onAbortCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onCanPlay?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onCanPlayCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onCanPlayThrough?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onCanPlayThroughCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onDurationChange?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onDurationChangeCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEmptied?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEmptiedCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEncrypted?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEncryptedCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEnded?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onEndedCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadedData?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadedDataCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadedMetadata?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadedMetadataCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadStart?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onLoadStartCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPause?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPauseCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPlay?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPlayCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPlaying?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onPlayingCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onProgress?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onProgressCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onRateChange?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onRateChangeCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSeeked?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSeekedCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSeeking?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSeekingCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onStalled?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onStalledCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSuspend?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSuspendCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onTimeUpdate?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onTimeUpdateCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onVolumeChange?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onVolumeChangeCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onWaiting?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onWaitingCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // MouseEvents - onClick?: MouseEventHandler | undefined; - onClickCapture?: MouseEventHandler | undefined; - onContextMenu?: MouseEventHandler | undefined; - onContextMenuCapture?: MouseEventHandler | undefined; - onDblClick?: MouseEventHandler | undefined; - onDblClickCapture?: MouseEventHandler | undefined; - onDrag?: DragEventHandler | undefined; - onDragCapture?: DragEventHandler | undefined; - onDragEnd?: DragEventHandler | undefined; - onDragEndCapture?: DragEventHandler | undefined; - onDragEnter?: DragEventHandler | undefined; - onDragEnterCapture?: DragEventHandler | undefined; - onDragExit?: DragEventHandler | undefined; - onDragExitCapture?: DragEventHandler | undefined; - onDragLeave?: DragEventHandler | undefined; - onDragLeaveCapture?: DragEventHandler | undefined; - onDragOver?: DragEventHandler | undefined; - onDragOverCapture?: DragEventHandler | undefined; - onDragStart?: DragEventHandler | undefined; - onDragStartCapture?: DragEventHandler | undefined; - onDrop?: DragEventHandler | undefined; - onDropCapture?: DragEventHandler | undefined; - onMouseDown?: MouseEventHandler | undefined; - onMouseDownCapture?: MouseEventHandler | undefined; - onMouseEnter?: MouseEventHandler | undefined; - onMouseEnterCapture?: MouseEventHandler | undefined; - onMouseLeave?: MouseEventHandler | undefined; - onMouseLeaveCapture?: MouseEventHandler | undefined; - onMouseMove?: MouseEventHandler | undefined; - onMouseMoveCapture?: MouseEventHandler | undefined; - onMouseOut?: MouseEventHandler | undefined; - onMouseOutCapture?: MouseEventHandler | undefined; - onMouseOver?: MouseEventHandler | undefined; - onMouseOverCapture?: MouseEventHandler | undefined; - onMouseUp?: MouseEventHandler | undefined; - onMouseUpCapture?: MouseEventHandler | undefined; + onClick?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onClickCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onContextMenu?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onContextMenuCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onDblClick?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onDblClickCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onDrag?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragEnd?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragEndCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragEnter?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragEnterCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragExit?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragExitCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragLeave?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragLeaveCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragOver?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragOverCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragStart?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDragStartCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDrop?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onDropCapture?: + | DragEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseDown?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseDownCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseEnter?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseEnterCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseLeave?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseLeaveCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseMove?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseMoveCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseOut?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseOutCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseOver?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseOverCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseUp?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; + onMouseUpCapture?: + | MouseEventHandler + | undefined + | AttributeHelper | undefined>; // Selection Events - onSelect?: GenericEventHandler | undefined; - onSelectCapture?: GenericEventHandler | undefined; + onSelect?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; + onSelectCapture?: + | GenericEventHandler + | undefined + | AttributeHelper | undefined>; // Touch Events - onTouchCancel?: TouchEventHandler | undefined; - onTouchCancelCapture?: TouchEventHandler | undefined; - onTouchEnd?: TouchEventHandler | undefined; - onTouchEndCapture?: TouchEventHandler | undefined; - onTouchMove?: TouchEventHandler | undefined; - onTouchMoveCapture?: TouchEventHandler | undefined; - onTouchStart?: TouchEventHandler | undefined; - onTouchStartCapture?: TouchEventHandler | undefined; + onTouchCancel?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchCancelCapture?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchEnd?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchEndCapture?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchMove?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchMoveCapture?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchStart?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; + onTouchStartCapture?: + | TouchEventHandler + | undefined + | AttributeHelper | undefined>; // Pointer Events - onPointerOver?: PointerEventHandler | undefined; - onPointerOverCapture?: PointerEventHandler | undefined; - onPointerEnter?: PointerEventHandler | undefined; - onPointerEnterCapture?: PointerEventHandler | undefined; - onPointerDown?: PointerEventHandler | undefined; - onPointerDownCapture?: PointerEventHandler | undefined; - onPointerMove?: PointerEventHandler | undefined; - onPointerMoveCapture?: PointerEventHandler | undefined; - onPointerUp?: PointerEventHandler | undefined; - onPointerUpCapture?: PointerEventHandler | undefined; - onPointerCancel?: PointerEventHandler | undefined; - onPointerCancelCapture?: PointerEventHandler | undefined; - onPointerOut?: PointerEventHandler | undefined; - onPointerOutCapture?: PointerEventHandler | undefined; - onPointerLeave?: PointerEventHandler | undefined; - onPointerLeaveCapture?: PointerEventHandler | undefined; - onGotPointerCapture?: PointerEventHandler | undefined; - onGotPointerCaptureCapture?: PointerEventHandler | undefined; - onLostPointerCapture?: PointerEventHandler | undefined; - onLostPointerCaptureCapture?: PointerEventHandler | undefined; + onPointerOver?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerOverCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerEnter?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerEnterCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerDown?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerDownCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerMove?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerMoveCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerUp?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerUpCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerCancel?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerCancelCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerOut?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerOutCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerLeave?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onPointerLeaveCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onGotPointerCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onGotPointerCaptureCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onLostPointerCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; + onLostPointerCaptureCapture?: + | PointerEventHandler + | undefined + | AttributeHelper | undefined>; // UI Events - onScroll?: UIEventHandler | undefined; - onScrollEnd?: UIEventHandler | undefined; - onScrollCapture?: UIEventHandler | undefined; + onScroll?: + | UIEventHandler + | undefined + | AttributeHelper | undefined>; + onScrollEnd?: + | UIEventHandler + | undefined + | AttributeHelper | undefined>; + onScrollCapture?: + | UIEventHandler + | undefined + | AttributeHelper | undefined>; // Wheel Events - onWheel?: WheelEventHandler | undefined; - onWheelCapture?: WheelEventHandler | undefined; + onWheel?: + | WheelEventHandler + | undefined + | AttributeHelper | undefined>; + onWheelCapture?: + | WheelEventHandler + | undefined + | AttributeHelper | undefined>; // Animation Events - onAnimationStart?: AnimationEventHandler | undefined; - onAnimationStartCapture?: AnimationEventHandler | undefined; - onAnimationEnd?: AnimationEventHandler | undefined; - onAnimationEndCapture?: AnimationEventHandler | undefined; - onAnimationIteration?: AnimationEventHandler | undefined; - onAnimationIterationCapture?: AnimationEventHandler | undefined; + onAnimationStart?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; + onAnimationStartCapture?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; + onAnimationEnd?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; + onAnimationEndCapture?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; + onAnimationIteration?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; + onAnimationIterationCapture?: + | AnimationEventHandler + | undefined + | AttributeHelper | undefined>; // Transition Events - onTransitionCancel?: TransitionEventHandler; - onTransitionCancelCapture?: TransitionEventHandler; - onTransitionEnd?: TransitionEventHandler; - onTransitionEndCapture?: TransitionEventHandler; - onTransitionRun?: TransitionEventHandler; - onTransitionRunCapture?: TransitionEventHandler; - onTransitionStart?: TransitionEventHandler; - onTransitionStartCapture?: TransitionEventHandler; + onTransitionCancel?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionCancelCapture?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionEnd?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionEndCapture?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionRun?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionRunCapture?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionStart?: + | TransitionEventHandler + | AttributeHelper | undefined>; + onTransitionStartCapture?: + | TransitionEventHandler + | AttributeHelper | undefined>; // PictureInPicture Events - onEnterPictureInPicture?: PictureInPictureEventHandler; - onEnterPictureInPictureCapture?: PictureInPictureEventHandler; - onLeavePictureInPicture?: PictureInPictureEventHandler; - onLeavePictureInPictureCapture?: PictureInPictureEventHandler; - onResize?: PictureInPictureEventHandler; - onResizeCapture?: PictureInPictureEventHandler; + onEnterPictureInPicture?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; + onEnterPictureInPictureCapture?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; + onLeavePictureInPicture?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; + onLeavePictureInPictureCapture?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; + onResize?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; + onResizeCapture?: + | PictureInPictureEventHandler + | AttributeHelper | undefined>; } // All the WAI-ARIA 1.1 attributes from https://www.w3.org/TR/wai-aria-1.1/ diff --git a/src/types.d.ts b/src/types.d.ts index 8c6a8d0..18e2d9a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,5 +1,7 @@ import { VelesDOMElementProps } from "./dom-types"; +import type { JSX } from "./jsx.d.ts"; + // an internal representation of DOM nodes in the tree // despite being DOM nodes, we still can track mounting/unmounting // (although it is not exposed at the moment) @@ -71,7 +73,7 @@ export type VelesElementProps = { // or a function in case we support reactivity // TODO: we can improve these types [htmlAttribute: string]: any; -} & VelesDOMElementProps; +} & JSX.HTMLAttributes; export type ComponentAPI = { // You can return a function from the mount callback, and it will be