Skip to content

Commit 12af453

Browse files
fix(dismissable-layer): events (#392)
* fix(dismissable-layer): events * fix: test
1 parent 1aebd09 commit 12af453

File tree

10 files changed

+230
-288
lines changed

10 files changed

+230
-288
lines changed

packages/components/alert-dialog/tests/__snapshots__/alert-dialog.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ exports[`OkuAlertDialog > Controlled > should be able to close 1`] = `
8686
8787
exports[`OkuAlertDialog > Controlled > should be able to open 1`] = `
8888
<body
89-
style=""
89+
style="pointer-events: none;"
9090
>
9191
<span
9292
data-oku-focus-guard=""
@@ -295,7 +295,7 @@ exports[`OkuAlertDialog > StyledVue > should be able to close 1`] = `
295295
296296
exports[`OkuAlertDialog > StyledVue > should be able to open 1`] = `
297297
<body
298-
style=""
298+
style="pointer-events: none;"
299299
>
300300
<span
301301
data-oku-focus-guard=""

packages/core/dismissable-layer/src/DismissableLayer.ts

Lines changed: 6 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ import {
44
useEscapeKeydown,
55
useForwardRef,
66
} from '@oku-ui/use-composable'
7-
import type { OkuElement, PrimitiveProps } from '@oku-ui/primitive'
87
import { Primitive, primitiveProps } from '@oku-ui/primitive'
9-
import type { Ref } from 'vue'
108
import {
119
computed,
1210
defineComponent,
1311
h,
1412
mergeProps,
15-
nextTick,
1613
onBeforeUnmount,
1714
onMounted,
1815
reactive,
@@ -27,108 +24,11 @@ import {
2724
useFocusoutSide,
2825
usePointerdownOutside,
2926
} from './util'
30-
31-
export const dismissableLayerContext = reactive({
32-
layersRoot: new Set<DismissableLayerElement>(),
33-
layersWithOutsidePointerEventsDisabled: new Set<DismissableLayerElement>(),
34-
branches: new Set<DismissableLayerElement>(),
35-
})
36-
37-
export const INJECT_UPDATE = 'dismissableLayer.update'
38-
export const POINTER_DOWN_OUTSIDE = 'dismissableLayer.pointerDownOutside'
39-
export const FOCUS_OUTSIDE = 'dismissableLayer.focusOutside'
27+
import type { DismissableLayerNativeElement, FocusBlurCaptureEvent, FocusCaptureEvent, PointerdownCaptureEvent } from './props'
28+
import { DISMISSABLE_NAME, INJECT_UPDATE, dismissableLayerContext, dismissableLayerProps } from './props'
4029

4130
let originalBodyPointerEvents: string
4231

43-
export const DISMISSABLE_NAME = 'OkuDismissableLayer'
44-
export const DismissableLayerProvideKey = Symbol('DismissableLayerProvide')
45-
46-
export type DismissableLayerNativeElement = OkuElement<'div'>
47-
export type DismissableLayerElement = HTMLDivElement
48-
49-
export type DismissableLayerProvideValue = {
50-
layers: Ref<Set<DismissableLayerElement>>
51-
layersWithOutsidePointerEventsDisabled: Ref<Set<DismissableLayerElement>>
52-
branches: Ref<Set<DismissableLayerElement>>
53-
}
54-
55-
export type PointerdownOutsideEvent = CustomEvent<{
56-
originalEvent: PointerEvent
57-
}>
58-
export type FocusoutSideEvent = CustomEvent<{ originalEvent: FocusEvent }>
59-
export type FocusCaptureEvent = CustomEvent<{ originalEvent: FocusEvent }>
60-
export type FocusBlurCaptureEvent = CustomEvent<{ originalEvent: FocusEvent }>
61-
export type PointerdownCaptureEvent = CustomEvent<{
62-
originalEvent: PointerEvent
63-
}>
64-
65-
export interface DismissableLayerProps extends PrimitiveProps {
66-
/**
67-
* When `true`, hover/focus/click interactions will be disabled on elements outside
68-
* the `DismissableLayer`. Users will need to click twice on outside elements to
69-
* interact with them: once to close the `DismissableLayer`, and again to trigger the element.
70-
*/
71-
disableOutsidePointerEvents?: boolean
72-
}
73-
74-
export type DismissableLayerEmits = {
75-
/**
76-
* Event handler called when the escape key is down.
77-
* Can be prevented.
78-
*/
79-
escapeKeyDown: [event: KeyboardEvent]
80-
/**
81-
* Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
82-
* Can be prevented.
83-
*/
84-
pointerdownOutside: [event: PointerdownOutsideEvent]
85-
/**
86-
* Event handler called when the focus moves outside of the `DismissableLayer`.
87-
* Can be prevented.
88-
*/
89-
focusoutSide: [event: FocusoutSideEvent]
90-
/**
91-
* Event handler called when an interaction happens outside the `DismissableLayer`.
92-
* Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
93-
* Can be prevented.
94-
*/
95-
interactOutside: [event: PointerdownOutsideEvent | FocusoutSideEvent]
96-
/**
97-
* Handler called when the `DismissableLayer` should be dismissed
98-
*/
99-
dismiss: []
100-
focusCapture: [event: FocusCaptureEvent]
101-
blurCapture: [event: FocusBlurCaptureEvent]
102-
pointerdownCapture: [event: PointerdownCaptureEvent]
103-
}
104-
105-
export const dismissableLayerProps = {
106-
props: {
107-
disableOutsidePointerEvents: {
108-
type: Boolean,
109-
default: false,
110-
},
111-
},
112-
113-
emits: {
114-
// eslint-disable-next-line unused-imports/no-unused-vars
115-
escapeKeyDown: (event: KeyboardEvent) => true,
116-
// eslint-disable-next-line unused-imports/no-unused-vars
117-
pointerdownOutside: (event: PointerdownOutsideEvent) => true,
118-
// eslint-disable-next-line unused-imports/no-unused-vars
119-
focusoutSide: (event: FocusoutSideEvent) => true,
120-
// eslint-disable-next-line unused-imports/no-unused-vars
121-
interactOutside: (event: PointerdownOutsideEvent | FocusoutSideEvent) => true,
122-
dismiss: () => true,
123-
// eslint-disable-next-line unused-imports/no-unused-vars
124-
focusCapture: (event: FocusCaptureEvent) => true,
125-
// eslint-disable-next-line unused-imports/no-unused-vars
126-
blurCapture: (event: FocusBlurCaptureEvent) => true,
127-
// eslint-disable-next-line unused-imports/no-unused-vars
128-
pointerdownCapture: (event: PointerdownCaptureEvent) => true,
129-
},
130-
}
131-
13232
const DismissableLayer = defineComponent({
13333
name: DISMISSABLE_NAME,
13434
inheritAttrs: false,
@@ -188,7 +88,7 @@ const DismissableLayer = defineComponent({
18888

18989
if (!event.defaultPrevented)
19090
emit('dismiss')
191-
}, ownerDocument.value)
91+
}, ownerDocument)
19292

19393
const focusoutSide = useFocusoutSide((event) => {
19494
const target = event.target as HTMLElement
@@ -204,7 +104,7 @@ const DismissableLayer = defineComponent({
204104

205105
if (!event.defaultPrevented)
206106
emit('dismiss')
207-
}, ownerDocument.value)
107+
}, ownerDocument)
208108

209109
useEscapeKeydown((event) => {
210110
const isHighestLayer = index.value === dismissableLayerContext.layersRoot.size - 1
@@ -214,9 +114,9 @@ const DismissableLayer = defineComponent({
214114

215115
emit('escapeKeyDown', event)
216116

217-
if (!event.defaultPrevented && props.onDismiss)
117+
if (!event.defaultPrevented)
218118
emit('dismiss')
219-
}, ownerDocument.value)
119+
}, ownerDocument)
220120

221121
watchEffect(async (onInvalidate) => {
222122
if (!node.value)
@@ -228,7 +128,6 @@ const DismissableLayer = defineComponent({
228128
= ownerDocument.value.body.style.pointerEvents
229129
ownerDocument.value.body.style.pointerEvents = 'none'
230130
}
231-
await nextTick()
232131
dismissableLayerContext.layersWithOutsidePointerEventsDisabled.add(node.value)
233132
}
234133

packages/core/dismissable-layer/src/DismissableLayerBranch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
} from '@oku-ui/primitive'
66
import { defineComponent, h, ref, watchEffect } from 'vue'
77
import { useComposedRefs, useForwardRef } from '@oku-ui/use-composable'
8-
import { dismissableLayerContext } from './DismissableLayer'
8+
import { dismissableLayerContext } from './props'
99

1010
const BRANCH_NAME = 'OkuDismissableLayerBranch'
1111
export type DismissableLayerBranchNaviteElement = OkuElement<'div'>

packages/core/dismissable-layer/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ export * from './DismissableLayerBranch'
22

33
export {
44
OkuDismissableLayer,
5-
dismissableLayerProps,
65
} from './DismissableLayer'
76

87
export type {
98
DismissableLayerProps,
109
DismissableLayerEmits,
11-
} from './DismissableLayer'
10+
} from './props'
11+
12+
export {
13+
dismissableLayerProps,
14+
} from './props'
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import type { OkuElement, PrimitiveProps } from '@oku-ui/primitive'
2+
import { type Ref, reactive } from 'vue'
3+
4+
export const dismissableLayerContext = reactive({
5+
layersRoot: new Set<DismissableLayerElement>(),
6+
layersWithOutsidePointerEventsDisabled: new Set<DismissableLayerElement>(),
7+
branches: new Set<DismissableLayerElement>(),
8+
})
9+
10+
export const INJECT_UPDATE = 'dismissableLayer.update'
11+
export const POINTER_DOWN_OUTSIDE = 'dismissableLayer.pointerdownOutside'
12+
export const FOCUS_OUTSIDE = 'dismissableLayer.focusoutSide'
13+
14+
export const DISMISSABLE_NAME = 'OkuDismissableLayer'
15+
export const DismissableLayerProvideKey = Symbol('DismissableLayerProvide')
16+
17+
export type DismissableLayerNativeElement = OkuElement<'div'>
18+
export type DismissableLayerElement = HTMLDivElement
19+
20+
export type DismissableLayerProvideValue = {
21+
layers: Ref<Set<DismissableLayerElement>>
22+
layersWithOutsidePointerEventsDisabled: Ref<Set<DismissableLayerElement>>
23+
branches: Ref<Set<DismissableLayerElement>>
24+
}
25+
26+
export type PointerdownOutsideEvent = CustomEvent<{
27+
originalEvent: PointerEvent
28+
}>
29+
export type FocusoutSideEvent = CustomEvent<{ originalEvent: FocusEvent }>
30+
export type FocusCaptureEvent = CustomEvent<{ originalEvent: FocusEvent }>
31+
export type FocusBlurCaptureEvent = CustomEvent<{ originalEvent: FocusEvent }>
32+
export type PointerdownCaptureEvent = CustomEvent<{
33+
originalEvent: PointerEvent
34+
}>
35+
36+
export interface DismissableLayerProps extends PrimitiveProps {
37+
/**
38+
* When `true`, hover/focus/click interactions will be disabled on elements outside
39+
* the `DismissableLayer`. Users will need to click twice on outside elements to
40+
* interact with them: once to close the `DismissableLayer`, and again to trigger the element.
41+
*/
42+
disableOutsidePointerEvents?: boolean
43+
}
44+
45+
export type DismissableLayerEmits = {
46+
/**
47+
* Event handler called when the escape key is down.
48+
* Can be prevented.
49+
*/
50+
escapeKeyDown: [event: KeyboardEvent]
51+
/**
52+
* Event handler called when the a `pointerdown` event happens outside of the `DismissableLayer`.
53+
* Can be prevented.
54+
*/
55+
pointerdownOutside: [event: PointerdownOutsideEvent]
56+
/**
57+
* Event handler called when the focus moves outside of the `DismissableLayer`.
58+
* Can be prevented.
59+
*/
60+
focusoutSide: [event: FocusoutSideEvent]
61+
/**
62+
* Event handler called when an interaction happens outside the `DismissableLayer`.
63+
* Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
64+
* Can be prevented.
65+
*/
66+
interactOutside: [event: PointerdownOutsideEvent | FocusoutSideEvent]
67+
/**
68+
* Handler called when the `DismissableLayer` should be dismissed
69+
*/
70+
dismiss: []
71+
focusCapture: [event: FocusCaptureEvent]
72+
blurCapture: [event: FocusBlurCaptureEvent]
73+
pointerdownCapture: [event: PointerdownCaptureEvent]
74+
}
75+
76+
export const dismissableLayerProps = {
77+
props: {
78+
disableOutsidePointerEvents: {
79+
type: Boolean,
80+
default: false,
81+
},
82+
},
83+
84+
emits: {
85+
// eslint-disable-next-line unused-imports/no-unused-vars
86+
escapeKeyDown: (event: KeyboardEvent) => true,
87+
// eslint-disable-next-line unused-imports/no-unused-vars
88+
pointerdownOutside: (event: PointerdownOutsideEvent) => true,
89+
// eslint-disable-next-line unused-imports/no-unused-vars
90+
focusoutSide: (event: FocusoutSideEvent) => true,
91+
// eslint-disable-next-line unused-imports/no-unused-vars
92+
interactOutside: (event: PointerdownOutsideEvent | FocusoutSideEvent) => true,
93+
dismiss: () => true,
94+
// eslint-disable-next-line unused-imports/no-unused-vars
95+
focusCapture: (event: FocusCaptureEvent) => true,
96+
// eslint-disable-next-line unused-imports/no-unused-vars
97+
blurCapture: (event: FocusBlurCaptureEvent) => true,
98+
// eslint-disable-next-line unused-imports/no-unused-vars
99+
pointerdownCapture: (event: PointerdownCaptureEvent) => true,
100+
},
101+
}

packages/core/dismissable-layer/src/util.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('useFocusoutSide', () => {
1818

1919
document.dispatchEvent(new FocusEvent('focusin'))
2020

21-
expect(onFocusoutSide).toHaveBeenCalled()
21+
expect(onFocusoutSide).not.toHaveBeenCalled()
2222
})
2323

2424
it('should not call onFocusoutSide when focusin event happens inside', () => {
@@ -30,7 +30,6 @@ describe('useFocusoutSide', () => {
3030
return { events }
3131
},
3232
})
33-
3433
// Simulate focusin event inside the component
3534
wrapper.find('button').trigger('focusin')
3635

0 commit comments

Comments
 (0)