From 2c09162fc0cf4ffaccbb9dafc5f45abd7ecce5cb Mon Sep 17 00:00:00 2001 From: Ryan Gossiaux Date: Mon, 27 Dec 2021 22:00:10 -1000 Subject: [PATCH] Initial Menu tests --- src/lib/components/menu/menu.test.ts | 888 +++++++++++++++++++++++++ src/lib/test-utils/TestRenderer.svelte | 4 + 2 files changed, 892 insertions(+) create mode 100644 src/lib/components/menu/menu.test.ts diff --git a/src/lib/components/menu/menu.test.ts b/src/lib/components/menu/menu.test.ts new file mode 100644 index 0000000..c2f94df --- /dev/null +++ b/src/lib/components/menu/menu.test.ts @@ -0,0 +1,888 @@ +import { assertActiveElement, assertMenu, assertMenuButton, assertMenuButtonLinkedWithMenu, assertMenuItem, assertMenuLinkedWithMenuItem, assertNoActiveMenuItem, getMenu, getMenuButton, getMenuItems, MenuState } from "$lib/test-utils/accessibility-assertions"; +import { render } from "@testing-library/svelte"; +import { Menu, MenuButton, MenuItem, MenuItems } from "."; +import { suppressConsoleLogs } from "$lib/test-utils/suppress-console-logs"; +import TestRenderer from "$lib/test-utils/TestRenderer.svelte"; +import { click, Keys, mouseMove, press } from "$lib/test-utils/interactions"; +import { Transition, TransitionChild } from "../transitions"; +import TransitionDebug from "$lib/components/disclosure/_TransitionDebug.svelte"; +import Div from "$lib/internal/elements/Div.svelte"; +import Form from "$lib/internal/elements/Form.svelte"; + +let id = 0; +jest.mock('../../hooks/use-id', () => { + return { + useId: jest.fn(() => ++id), + } +}) + +beforeEach(() => id = 0) +beforeAll(() => { + // jest.spyOn(window, 'requestAnimationFrame').mockImplementation(setImmediate as any) + // jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(clearImmediate as any) +}) +afterAll(() => jest.restoreAllMocks()) + +describe('Safe guards', () => { + it.each([ + ['MenuButton', MenuButton], + ['MenuItems', MenuItems], + ['MenuItem', MenuItem], + ])( + 'should error when we are using a <%s /> without a parent ', + suppressConsoleLogs((name, Component) => { + expect(() => render(Component)).toThrowError( + `<${name} /> is missing a parent component.` + ) + }) + ) + + it( + 'should be possible to render a Menu without crashing', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + }) + ) +}) + +describe('Rendering', () => { + // describe('Menu', () => { + // it( + // 'should be possible to render a Menu using a render prop', + // suppressConsoleLogs(async () => { + // render( + // + // {({ open }) => ( + // <> + // Trigger + // {open && ( + // + // Item A + // Item B + // Item C + // + // )} + // + // )} + // + // ) + + // assertMenuButton({ + // state: MenuState.InvisibleUnmounted, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ state: MenuState.InvisibleUnmounted }) + + // await click(getMenuButton()) + + // assertMenuButton({ + // state: MenuState.Visible, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ state: MenuState.Visible }) + // }) + // ) + // }) + + describe('Menu.Button', () => { + // it( + // 'should be possible to render a Menu.Button using a render prop', + // suppressConsoleLogs(async () => { + // render( + // + // {JSON.stringify} + // + // Item A + // Item B + // Item C + // + // + // ) + + // assertMenuButton({ + // state: MenuState.InvisibleUnmounted, + // attributes: { id: 'headlessui-menu-button-1' }, + // textContent: JSON.stringify({ open: false }), + // }) + // assertMenu({ state: MenuState.InvisibleUnmounted }) + + // await click(getMenuButton()) + + // assertMenuButton({ + // state: MenuState.Visible, + // attributes: { id: 'headlessui-menu-button-1' }, + // textContent: JSON.stringify({ open: true }), + // }) + // assertMenu({ state: MenuState.Visible }) + // }) + // ) + + // it( + // 'should be possible to render a Menu.Button using a render prop and an `as` prop', + // suppressConsoleLogs(async () => { + // render( + // + // + // {JSON.stringify} + // + // + // Item A + // Item B + // Item C + // + // + // ) + + // assertMenuButton({ + // state: MenuState.InvisibleUnmounted, + // attributes: { id: 'headlessui-menu-button-1' }, + // textContent: JSON.stringify({ open: false }), + // }) + // assertMenu({ state: MenuState.InvisibleUnmounted }) + + // await click(getMenuButton()) + + // assertMenuButton({ + // state: MenuState.Visible, + // attributes: { id: 'headlessui-menu-button-1' }, + // textContent: JSON.stringify({ open: true }), + // }) + // assertMenu({ state: MenuState.Visible }) + // }) + // ) + + describe('`type` attribute', () => { + it('should set the `type` to "button" by default', async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + ]], + ] + }) + + expect(getMenuButton()).toHaveAttribute('type', 'button') + }) + + it('should not set the `type` to "button" if it already contains a `type`', async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, { type: "submit" }, "Trigger"], + ]], + ] + }) + + expect(getMenuButton()).toHaveAttribute('type', 'submit') + }) + + it('should not set the type if the "as" prop is not a "button"', async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, { as: "div" }, "Trigger"], + ]], + ] + }) + + expect(getMenuButton()).not.toHaveAttribute('type') + }) + + }) + }) + + describe('Menu.Items', () => { + // it( + // 'should be possible to render Menu.Items using a render prop', + // suppressConsoleLogs(async () => { + // render( + // + // Trigger + // + // {data => ( + // <> + // {JSON.stringify(data)} + // + // )} + // + // + // ) + + // assertMenuButton({ + // state: MenuState.InvisibleUnmounted, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ state: MenuState.InvisibleUnmounted }) + + // await click(getMenuButton()) + + // assertMenuButton({ + // state: MenuState.Visible, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ + // state: MenuState.Visible, + // textContent: JSON.stringify({ open: true }), + // }) + // }) + // ) + + it('should be possible to always render the Menu.Items if we provide it a `static` prop', () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, { static: true }, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + // Let's verify that the Menu is already there + expect(getMenu()).not.toBe(null) + }) + + it('should be possible to use a different render strategy for the Menu.Items', async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, { unmount: false }, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenu({ state: MenuState.InvisibleHidden }) + + // Let's open the Menu, to see if it is not hidden anymore + await click(getMenuButton()) + + assertMenu({ state: MenuState.Visible }) + }) + }) + + // describe('Menu.Item', () => { + // it( + // 'should be possible to render a Menu.Item using a render prop', + // suppressConsoleLogs(async () => { + // render( + // + // Trigger + // + // {JSON.stringify} + // + // + // ) + + // assertMenuButton({ + // state: MenuState.InvisibleUnmounted, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ state: MenuState.InvisibleUnmounted }) + + // await click(getMenuButton()) + + // assertMenuButton({ + // state: MenuState.Visible, + // attributes: { id: 'headlessui-menu-button-1' }, + // }) + // assertMenu({ + // state: MenuState.Visible, + // textContent: JSON.stringify({ active: false, disabled: false }), + // }) + // }) + // ) + // }) +}) + +describe('Rendering composition', () => { + it( + 'should be possible to conditionally render classes (aka class can be a function?!)', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a", class: (bag: any) => JSON.stringify(bag) }, "Item A"], + [MenuItem, { as: "a", disabled: true, class: (bag: any) => JSON.stringify(bag) }, "Item B"], + [MenuItem, { as: "a", class: "no-special-treatment" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Open menu + await click(getMenuButton()) + + let items = getMenuItems() + + // Verify correct classNames + expect('' + items[0].classList).toEqual(JSON.stringify({ active: false, disabled: false })) + expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true })) + expect('' + items[2].classList).toEqual('no-special-treatment') + + // Double check that nothing is active + assertNoActiveMenuItem() + + // Make the first item active + await press(Keys.ArrowDown) + + // Verify the classNames + expect('' + items[0].classList).toEqual(JSON.stringify({ active: true, disabled: false })) + expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true })) + expect('' + items[2].classList).toEqual('no-special-treatment') + + // Double check that the first item is the active one + assertMenuLinkedWithMenuItem(items[0]) + + // Let's go down, this should go to the third item since the second item is disabled! + await press(Keys.ArrowDown) + + // Verify the classNames + expect('' + items[0].classList).toEqual(JSON.stringify({ active: false, disabled: false })) + expect('' + items[1].classList).toEqual(JSON.stringify({ active: false, disabled: true })) + expect('' + items[2].classList).toEqual('no-special-treatment') + + // Double check that the last item is the active one + assertMenuLinkedWithMenuItem(items[2]) + }) + ) + + it( + 'should be possible to swap the menu item with a button for example', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "button" }, "Item A"], + [MenuItem, { as: "button" }, "Item B"], + [MenuItem, { as: "button" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Open menu + await click(getMenuButton()) + + // Verify items are buttons now + let items = getMenuItems() + items.forEach(item => assertMenuItem(item, { tag: 'button' })) + }) + ) + + it( + 'should mark all the elements between Menu.Items and Menu.Item with role none', + suppressConsoleLogs(async () => { + render + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [Div, { class: "outer" }, [ + [MenuItems, {}, [ + [Div, { class: "py-1 inner" }, [ + [MenuItem, { as: "button" }, "Item A"], + [MenuItem, { as: "button" }, "Item B"], + ]], + [Div, { class: "py-1 inner" }, [ + [MenuItem, { as: "button" }, "Item C"], + [MenuItem, {}, [ + [Div, {}, [ + [Div, { class: "outer" }, "Item D"] + ]] + ]] + ]], + [Div, { class: "py-1 inner" }, [ + [Form, { class: "inner" }, [ + [MenuItem, { as: "button" }, "Item E"] + ]] + ]] + ]] + ]] + ]], + ] + }) + + // Open menu + await click(getMenuButton()) + + expect.hasAssertions() + + document.querySelectorAll('.outer').forEach(element => { + expect(element).not.toHaveAttribute('role', 'none') + }) + + document.querySelectorAll('.inner').forEach(element => { + expect(element).toHaveAttribute('role', 'none') + }) + }) + ) +}) + +describe('Composition', () => { + it.skip( + 'should be possible to wrap the Menu.Items with a Transition component', + suppressConsoleLogs(async () => { + let orderFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [TransitionDebug, { name: "Menu", fn: orderFn }], + [Transition, {}, [ + [TransitionDebug, { name: "Transition", fn: orderFn }], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, [ + "Item A", + [TransitionDebug, { name: "MenuItem", fn: orderFn }], + ]] + ]] + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + await click(getMenuButton()) + + assertMenuButton({ + state: MenuState.Visible, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ + state: MenuState.Visible, + textContent: "Item A", + }) + + await click(getMenuButton()) + + // Verify that we tracked the `mounts` and `unmounts` in the correct order + expect(orderFn.mock.calls).toEqual([ + ['Mounting - Menu'], + ['Mounting - Transition'], + ['Mounting - MenuItem'], + ['Unmounting - Transition'], + ['Unmounting - MenuItem'], + ]) + }) + ) + + it.skip( + 'should be possible to wrap the Menu.Items with a Transition.Child component', + suppressConsoleLogs(async () => { + let orderFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [TransitionDebug, { name: "Menu", fn: orderFn }], + [TransitionChild, {}, [ + [TransitionDebug, { name: "Transition", fn: orderFn }], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, [ + "Item A", + [TransitionDebug, { name: "MenuItem", fn: orderFn }], + ]] + ]] + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + await click(getMenuButton()) + + assertMenuButton({ + state: MenuState.Visible, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ + state: MenuState.Visible, + textContent: "Item A", + }) + + await click(getMenuButton()) + + // Verify that we tracked the `mounts` and `unmounts` in the correct order + expect(orderFn.mock.calls).toEqual([ + ['Mounting - Menu'], + ['Mounting - Transition'], + ['Mounting - MenuItem'], + ['Unmounting - Transition'], + ['Unmounting - MenuItem'], + ]) + }) + ) +}) + +describe('Keyboard interactions', () => { + describe('`Enter` key', () => { + it( + 'should be possible to open the menu with Enter', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Open menu + await press(Keys.Enter) + + // Verify it is open + assertMenuButton({ state: MenuState.Visible }) + assertMenu({ + state: MenuState.Visible, + attributes: { id: 'headlessui-menu-items-2' }, + }) + assertMenuButtonLinkedWithMenu() + + // Verify we have menu items + let items = getMenuItems() + expect(items).toHaveLength(3) + items.forEach(item => assertMenuItem(item)) + + // Verify that the first menu item is active + assertMenuLinkedWithMenuItem(items[0]) + }) + ) + + it( + 'should not be possible to open the menu with Enter when the button is disabled', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, { disabled: true }, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Try to open the menu + await press(Keys.Enter) + + // Verify it is still closed + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + }) + ) + + it( + 'should have no active menu item when there are no menu items at all', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems] + ]], + ] + }) + + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Open menu + await press(Keys.Enter) + assertMenu({ state: MenuState.Visible }) + + assertNoActiveMenuItem() + }) + ) + + it( + 'should focus the first non disabled menu item when opening with Enter', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a", disabled: true }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Open menu + await press(Keys.Enter) + + let items = getMenuItems() + + // Verify that the first non-disabled menu item is active + assertMenuLinkedWithMenuItem(items[1]) + }) + ) + + it( + 'should focus the first non disabled menu item when opening with Enter (jump over multiple disabled ones)', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a", disabled: true }, "Item A"], + [MenuItem, { as: "a", disabled: true }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Open menu + await press(Keys.Enter) + + let items = getMenuItems() + + // Verify that the first non-disabled menu item is active + assertMenuLinkedWithMenuItem(items[2]) + }) + ) + + it( + 'should have no active menu item upon Enter key press, when there are no non-disabled menu items', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a", disabled: true }, "Item A"], + [MenuItem, { as: "a", disabled: true }, "Item B"], + [MenuItem, { as: "a", disabled: true }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Focus the button + getMenuButton()?.focus() + + // Open menu + await press(Keys.Enter) + + assertNoActiveMenuItem() + }) + ) + + it( + 'should be possible to close the menu with Enter when there is no active menuitem', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a" }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Open menu + await click(getMenuButton()) + + // Verify it is open + assertMenuButton({ state: MenuState.Visible }) + + // Close menu + await press(Keys.Enter) + + // Verify it is closed + assertMenuButton({ state: MenuState.InvisibleUnmounted }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Verify the button is focused again + assertActiveElement(getMenuButton()) + }) + ) + + it( + 'should be possible to close the menu with Enter and invoke the active menu item', + suppressConsoleLogs(async () => { + let clickHandler = jest.fn() + render( + TestRenderer, { + allProps: [ + [Menu, {}, [ + [MenuButton, {}, "Trigger"], + [MenuItems, {}, [ + [MenuItem, { as: "a", onClick: clickHandler }, "Item A"], + [MenuItem, { as: "a" }, "Item B"], + [MenuItem, { as: "a" }, "Item C"], + ]] + ]], + ] + }) + + assertMenuButton({ + state: MenuState.InvisibleUnmounted, + attributes: { id: 'headlessui-menu-button-1' }, + }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Open menu + await click(getMenuButton()) + + // Verify it is open + assertMenuButton({ state: MenuState.Visible }) + + // Activate the first menu item + let items = getMenuItems() + await mouseMove(items[0]) + + // Close menu, and invoke the item + await press(Keys.Enter) + + // Verify it is closed + assertMenuButton({ state: MenuState.InvisibleUnmounted }) + assertMenu({ state: MenuState.InvisibleUnmounted }) + + // Verify the button is focused again + assertActiveElement(getMenuButton()) + + // Verify the "click" went through on the `a` tag + expect(clickHandler).toHaveBeenCalled() + }) + ) + }) + +}) diff --git a/src/lib/test-utils/TestRenderer.svelte b/src/lib/test-utils/TestRenderer.svelte index 7fa3ac7..a0f27e1 100644 --- a/src/lib/test-utils/TestRenderer.svelte +++ b/src/lib/test-utils/TestRenderer.svelte @@ -6,6 +6,7 @@ onFocus?: HandlerType; onKeydown?: HandlerType; onSubmit?: HandlerType; + onClick?: HandlerType; } type SingleComponent = | string @@ -38,6 +39,7 @@ let onFocus: HandlerType = () => {}; let onKeydown: HandlerType = () => {}; let onSubmit: HandlerType = () => {}; + let onClick: HandlerType = () => {}; if (allProps && typeof allProps !== "string" && isSingleComponent(allProps)) { ({ onChange = onChange, @@ -45,6 +47,7 @@ onFocus = onFocus, onKeydown = onKeydown, onSubmit = onSubmit, + onClick = onClick, ...spreadProps } = allProps[1] || {}); } @@ -63,6 +66,7 @@ on:focus={onFocus} on:keydown={onKeydown} on:submit={onSubmit} + on:click={onClick} >