-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #299 from studiometa/feature/action-multiple-events
[Feature] Action: add support for multiple events
- Loading branch information
Showing
13 changed files
with
396 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
packages/docs/components/atoms/Action/stories/multiple-events/app.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Base, createApp } from '@studiometa/js-toolkit'; | ||
import { Action, Transition } from '@studiometa/ui'; | ||
|
||
class App extends Base { | ||
static config = { | ||
name: 'App', | ||
components: { | ||
Action, | ||
Transition, | ||
}, | ||
}; | ||
} | ||
|
||
export default createApp(App, document.body); |
8 changes: 8 additions & 0 deletions
8
packages/docs/components/atoms/Action/stories/multiple-events/app.twig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<button | ||
data-component="Action" | ||
data-option-on:click.stop="target.$el.textContent = 'Clicked'" | ||
data-option-on:mouseenter="target.$el.textContent = 'Hovered'" | ||
data-option-on:mouseleave="target.$el.textContent = 'Hover and click me'" | ||
class="px-4 py-2 rounded bg-blue-400 dark:bg-blue-600"> | ||
Hover and click me | ||
</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Base } from '@studiometa/js-toolkit'; | ||
|
||
export class Foo extends Base { | ||
static config = { | ||
name: 'Foo', | ||
}; | ||
} | ||
|
||
export class Bar extends Base { | ||
static config = { | ||
name: 'Bar', | ||
}; | ||
} | ||
|
||
export class Baz extends Base { | ||
static config = { | ||
name: 'Baz', | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import { describe, it, vi, expect, afterEach } from 'vitest'; | ||
import { Action, Target } from '@studiometa/ui'; | ||
import { ActionEvent } from '#private/atoms/Action/ActionEvent.js'; | ||
import { h, mount, destroy, Foo } from '#test-utils'; | ||
|
||
describe('The Action component', () => { | ||
it('should define a callable effect property based on the effect option', async () => { | ||
const spy = vi.spyOn(console, 'log'); | ||
spy.mockImplementation(() => {}); | ||
const actionEvent = new ActionEvent(new Action(h('div')), 'click', 'console.log(ctx)'); | ||
actionEvent.effect('foo'); | ||
expect(spy).toHaveBeenCalledTimes(1); | ||
expect(spy).toHaveBeenCalledWith('foo'); | ||
spy.mockRestore(); | ||
}); | ||
|
||
it('should return a callable function from the effect property', async () => { | ||
const spy = vi.spyOn(console, 'log'); | ||
spy.mockImplementation(() => {}); | ||
const actionEvent = new ActionEvent( | ||
new Action(h('div')), | ||
'click', | ||
'(...args) => console.log(...args)', | ||
); | ||
const callback = actionEvent.effect(); | ||
expect(typeof callback).toBe('function'); | ||
callback('foo'); | ||
expect(spy).toHaveBeenCalledTimes(1); | ||
expect(spy).toHaveBeenCalledWith('foo'); | ||
spy.mockRestore(); | ||
}); | ||
|
||
it('should resolve targets to self if option is not set', async () => { | ||
const action = new Action(h('div')); | ||
const actionEvent = new ActionEvent(action, 'click', '(...args) => console.log(...args)'); | ||
expect(actionEvent.targets).toEqual([{ Action: action }]); | ||
}); | ||
|
||
it('should resolve single target', async () => { | ||
const action = new Action(h('div')); | ||
const target = new Target(h('div')); | ||
await mount(action, target); | ||
const actionEvent = new ActionEvent(action, 'click', 'Target -> target'); | ||
expect(actionEvent.targets).toEqual([{ Target: target }]); | ||
await destroy(action, target); | ||
}); | ||
|
||
it('should resolve multiple targets', async () => { | ||
const action = new Action(h('div')); | ||
const target = new Target(h('div')); | ||
const foo = new Foo(h('div')); | ||
await mount(action, target, foo); | ||
const actionEvent = new ActionEvent(action, 'click', 'Target Foo -> target'); | ||
expect(actionEvent.targets).toEqual([{ Target: target }, { Foo: foo }]); | ||
await destroy(action, target, foo); | ||
}); | ||
|
||
it('should resolve targets with selectors', async () => { | ||
const action = new Action(h('div')); | ||
const targetA = new Target(h('div', { id: 'a' })); | ||
const targetB = new Target(h('div')); | ||
await mount(action, targetA, targetB); | ||
const actionEvent = new ActionEvent(action, 'click', 'Target(#a) -> target'); | ||
expect(actionEvent.targets).toEqual([{ Target: targetA }]); | ||
await destroy(action, targetA, targetB); | ||
}); | ||
|
||
it.todo( | ||
'should fail to resolve targets silently when the target string can not be parsed', | ||
async () => { | ||
// @todo | ||
}, | ||
); | ||
|
||
it('should prevent default and stop propagation if modifiers specified', async () => { | ||
const action = new Action(h('div')); | ||
await mount(action); | ||
const actionEvent = new ActionEvent(action, 'click.prevent.stop', 'target'); | ||
actionEvent.attachEvent(); | ||
const event = new Event('click'); | ||
const preventSpy = vi.spyOn(event, 'preventDefault'); | ||
const stopSpy = vi.spyOn(event, 'stopPropagation'); | ||
action.$el.dispatchEvent(event); | ||
expect(preventSpy).toHaveBeenCalledTimes(1); | ||
expect(stopSpy).toHaveBeenCalledTimes(1); | ||
await destroy(action); | ||
preventSpy.mockRestore(); | ||
stopSpy.mockRestore(); | ||
}); | ||
|
||
it('should configure the addEventListener options if modifiers specified', async () => { | ||
const action = new Action(h('div')); | ||
await mount(action); | ||
const actionEvent = new ActionEvent(action, 'click.capture.once.passive', 'target'); | ||
const addEventSpy = vi.spyOn(action.$el, 'addEventListener'); | ||
actionEvent.attachEvent(); | ||
expect(addEventSpy).toHaveBeenCalledTimes(1); | ||
expect(addEventSpy).toHaveBeenCalledWith('click', actionEvent, { | ||
capture: true, | ||
once: true, | ||
passive: true, | ||
}); | ||
await destroy(action); | ||
addEventSpy.mockRestore(); | ||
}); | ||
|
||
it('should warn when the effect throws an error', async () => { | ||
const action = new Action(h('div')); | ||
const warnSpy = vi.spyOn(action, '$warn'); | ||
const actionEvent = new ActionEvent(action, 'click', '() => consol.log()'); | ||
actionEvent.attachEvent(); | ||
action.$el.dispatchEvent(new Event('click')); | ||
expect(warnSpy).toHaveBeenCalledTimes(1); | ||
warnSpy.mockRestore(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.