Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit 10b6026

Browse files
committed
chore: more preogress debugging focus lock
1 parent 980d708 commit 10b6026

File tree

6 files changed

+180
-85
lines changed

6 files changed

+180
-85
lines changed

packages/c-focus-lock/src/c-focus-lock.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,16 @@ export interface FocusLockProps extends UseFocusLockOptions {
2727
/**
2828
* Element to which to send focus when focus trap has been deacivated
2929
*/
30-
finalFocusRef: RefProp
30+
finalFocusRef?: RefProp
3131
/**
3232
* Element to which to send focus when focus trap has been activated
3333
*/
34-
initialFocusRef: RefProp
35-
/**
36-
* Disables focus trapping when set to `true`.
37-
*/
38-
isActive: boolean
34+
initialFocusRef?: RefProp
3935
/**
4036
* If `true`, the first focuable element within the `contentRef`
4137
* will be auto-focused once `CFocusLock` mounts
4238
*/
43-
autoFocus: boolean
39+
autoFocus?: boolean
4440
}
4541

4642
export const CFocusLock = defineComponent({
@@ -53,7 +49,6 @@ export const CFocusLock = defineComponent({
5349
initialFocusRef: [String, Function] as PropType<
5450
FocusLockProps['initialFocusRef']
5551
>,
56-
isActive: Boolean as PropType<FocusLockProps['isActive']>,
5752
autoFocus: {
5853
type: Boolean as PropType<FocusLockProps['autoFocus']>,
5954
default: true,

packages/c-focus-lock/src/use-focus-lock.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { MaybeElementRef, unrefElement, useRef } from '@chakra-ui/vue-utils'
2-
import { AnyFunction, focus, getFirstFocusable } from '@chakra-ui/utils'
2+
import {
3+
AnyFunction,
4+
focus,
5+
getAllFocusable,
6+
getFirstFocusable,
7+
} from '@chakra-ui/utils'
38
import { watch, ref, Ref, UnwrapRef, onBeforeUnmount, nextTick } from 'vue'
49
import {
510
ActivateOptions,
@@ -63,6 +68,11 @@ export interface UseFocusLockReturn {
6368
*/
6469
initialFocus: (el: UnwrapRef<MaybeElementRef>) => void
6570

71+
/**
72+
* Node ref of the actual content node towhich focus lock should be scoped
73+
*/
74+
content: (el: UnwrapRef<MaybeElementRef>) => void
75+
6676
/**
6777
* Node ref getter for focus lock element
6878
*/
@@ -82,6 +92,7 @@ export function useFocusLock(
8292

8393
const [lock, lockEl] = useRef()
8494
const [initialFocus, initialFocusEl] = useRef()
95+
const [content, contentEl] = useRef()
8596

8697
const { immediate, ...focusLockOptions } = options
8798

@@ -107,6 +118,8 @@ export function useFocusLock(
107118
}
108119
}
109120

121+
watch(contentEl, (el) => console.log('contentEl', el))
122+
110123
watch(
111124
lockEl,
112125
async (el) => {
@@ -122,7 +135,16 @@ export function useFocusLock(
122135
// may not yet be active. So just in case,
123136
// There's a fallback call here to focus the
124137
// element after the initial focus element is focused.
125-
const initialFocus = initialFocusEl.value ?? getFirstFocusable(el)
138+
let initialFocus = initialFocusEl.value ?? getFirstFocusable(el)
139+
if (initialFocusEl.value) {
140+
initialFocus = initialFocusEl.value
141+
} else {
142+
const focusables = getAllFocusable(contentEl.value || el)
143+
if (focusables.length) {
144+
initialFocus = focusables[0]
145+
console.log(focusables)
146+
}
147+
}
126148
console.log('initialFocusElement', initialFocus)
127149
setTimeout(() => focus(initialFocus))
128150

@@ -156,5 +178,6 @@ export function useFocusLock(
156178
deactivate,
157179
pause,
158180
unpause,
181+
content,
159182
}
160183
}

packages/c-modal/examples/base-c-modal.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
h="full"
77
w="100%"
88
>
9-
<c-button @click="isOpen = true" variant="luxury">Checkout</c-button>
9+
<c-button @click="isOpen = true">Checkout</c-button>
1010
<!-- eslint-disable-next-line -->
1111
<c-modal v-model:is-open="isOpen">
1212
<c-modal-overlay />

packages/c-modal/src/c-modal.ts

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import {
1818
toRefs,
1919
computed,
2020
ToRefs,
21-
unref,
22-
ref,
2321
mergeProps,
24-
Fragment,
22+
onMounted,
23+
watchEffect,
24+
UnwrapRef,
2525
watch,
26+
ref,
27+
cloneVNode,
2628
} from 'vue'
2729
import {
2830
chakra,
@@ -33,18 +35,26 @@ import {
3335
} from '@chakra-ui/vue-system'
3436
import { createContext, TemplateRef } from '@chakra-ui/vue-utils'
3537
import { CPortal } from '@chakra-ui/c-portal'
36-
import { FocusLockOptions, useFocusLock } from '@chakra-ui/c-focus-lock'
38+
import {
39+
CFocusLock,
40+
FocusLockProps,
41+
useFocusLock,
42+
} from '@chakra-ui/c-focus-lock'
3743
import { CScrollLock } from '@chakra-ui/c-scroll-lock'
3844
import { CMotion } from '@chakra-ui/c-motion'
3945

4046
import { useModal, UseModalOptions, UseModalReturn } from './use-modal'
4147
import { focus, FocusableElement } from '@chakra-ui/utils'
48+
import { FocusTarget } from 'focus-trap'
4249

4350
type ScrollBehavior = 'inside' | 'outside'
4451
type MotionPreset = 'slideInBottom' | 'slideInRight' | 'scale' | 'none'
4552

4653
export interface ModalOptions
47-
extends Omit<FocusLockOptions, 'enabled' | 'closeModal' | 'handleEscape'> {
54+
extends Omit<
55+
FocusLockProps,
56+
'enabled' | 'closeModal' | 'isActive' | 'handleEscape'
57+
> {
4858
/**
4959
* If `true`, the modal will be centered on screen.
5060
* @default false
@@ -60,7 +70,7 @@ export interface ModalOptions
6070
scrollBehavior?: ScrollBehavior
6171
}
6272

63-
export interface CModalProps extends UseModalOptions, ModalOptions {
73+
export interface CModalProps extends UnwrapRef<UseModalOptions>, ModalOptions {
6474
/**
6575
* If `true`, the modal will display
6676
*
@@ -85,15 +95,7 @@ export interface CModalProps extends UseModalOptions, ModalOptions {
8595
*
8696
* @default true
8797
*/
88-
autoFocus?: boolean
89-
/**
90-
* The `ref` of element to receive focus when the modal opens.
91-
*/
92-
initialFocusRef?: () => FocusableElement
93-
/**
94-
* The `ref` of element to receive focus when the modal closes.
95-
*/
96-
finalFocusRef?: () => FocusableElement
98+
autoFocus: boolean
9799
/**
98100
* If `true`, the modal will return focus to the element that triggered it when it closes.
99101
* @default true
@@ -123,7 +125,18 @@ export interface CModalProps extends UseModalOptions, ModalOptions {
123125
motionPreset?: MotionPreset
124126
}
125127

126-
type IUseModalOptions = ToRefs<Omit<CModalProps, 'closeModal' | 'handleEscape'>>
128+
type IUseModalOptions = ToRefs<
129+
Omit<
130+
CModalProps,
131+
| 'closeModal'
132+
| 'handleEscape'
133+
| 'preserveScrollBarGap'
134+
| 'allowPinchZoom'
135+
| 'motionPreset'
136+
| 'trapFocus'
137+
| 'autoFocus'
138+
>
139+
>
127140

128141
interface CModalContext extends IUseModalOptions, UseModalReturn {
129142
// /** The transition to be used for the CModal */
@@ -204,11 +217,11 @@ export const CModal = defineComponent({
204217
}
205218

206219
const styles = useMultiStyleConfig('Modal', mergeProps(props, attrs))
207-
const modalOptions = reactive({
208-
...props,
220+
const modalOptions = {
221+
...toRefs(reactive(props)),
209222
closeModal,
210223
handleEscape,
211-
})
224+
}
212225
const modal = useModal(modalOptions)
213226

214227
ModalContextProvider({
@@ -235,6 +248,8 @@ export const CModalFocusScope = defineComponent({
235248
initialFocusRef,
236249
returnFocusOnClose,
237250
finalFocusRef,
251+
dialogRef,
252+
dialogEl,
238253
blockScrollOnMount,
239254
} = useModalContext()
240255

@@ -244,31 +259,47 @@ export const CModalFocusScope = defineComponent({
244259
: finalFocusRef?.value
245260
)
246261

247-
const focusLockOptions: FocusLockOptions = reactive({
248-
enabled: isOpen.value,
249-
autoFocus: true,
250-
initialFocusRef: initialFocusRef?.value,
251-
returnFocus: returnFocusOnClose?.value,
252-
clickOutsideDeactivates: false,
253-
escapeDeactivates: false,
254-
onDeactivate: () => {
255-
if (finalFocusEl.value) {
256-
focus(finalFocusEl.value)
257-
}
258-
},
259-
})
262+
// const focusLockOptions = reactive({
263+
// immediate: true,
264+
// initialFocus: initialFocusRef?.value as FocusTarget,
265+
// returnFocus: returnFocusOnClose?.value,
266+
// clickOutsideDeactivates: false,
267+
// escapeDeactivates: false,
268+
// onDeactivate: () => {
269+
// if (finalFocusEl.value) {
270+
// focus(finalFocusEl.value as FocusableElement)
271+
// }
272+
// },
273+
// onActivate: () => {
274+
// console.log('focus lock activated')
275+
// },
276+
// })
277+
// })
260278

261-
const { lock } = useFocusLock(focusLockOptions)
279+
const contentRef = ref()
280+
281+
watch(contentRef, (el) => console.log('contentRef value updated', el), {
282+
flush: 'post',
283+
})
262284

263285
return () => {
264286
return h(
265-
CScrollLock,
287+
CFocusLock,
266288
{
267-
ref: lock,
268-
...attrs,
269-
enabled: blockScrollOnMount?.value,
289+
attrs,
270290
},
271-
slots
291+
() => [
292+
h(
293+
CScrollLock,
294+
{
295+
enabled: blockScrollOnMount?.value,
296+
},
297+
() =>
298+
slots.default?.({
299+
contentRef,
300+
})
301+
),
302+
]
272303
)
273304
}
274305
},
@@ -283,7 +314,13 @@ export const CModalContent = defineComponent({
283314
inheritAttrs: false,
284315
emits: ['click'],
285316
setup(_, { attrs, slots }) {
286-
const { dialogProps, dialogContainerProps, isOpen } = useModalContext()
317+
const {
318+
dialogProps,
319+
dialogContainerProps,
320+
dialogEl,
321+
dialogRef,
322+
isOpen,
323+
} = useModalContext()
287324
const styles = useStyles()
288325

289326
const dialogContainerStyles = computed<SystemStyleObject>(() => ({
@@ -305,8 +342,14 @@ export const CModalContent = defineComponent({
305342
...styles.value.dialog,
306343
}))
307344

345+
const dialogHack = ref()
346+
347+
watch(dialogHack, (el) => {
348+
console.log('fromCModalContent', el)
349+
})
350+
308351
return () =>
309-
h(CModalFocusScope, {}, () => [
352+
h(CModalFocusScope, null, () =>
310353
h(
311354
chakra('div', {
312355
label: 'modal__content-container',
@@ -321,22 +364,28 @@ export const CModalContent = defineComponent({
321364
},
322365
() => [
323366
isOpen.value &&
324-
h(
325-
chakra('div', {
326-
__css: dialogStyles.value,
327-
label: 'modal__content',
328-
}),
367+
cloneVNode(
368+
h(
369+
chakra('div', {
370+
__css: dialogStyles.value,
371+
label: 'modal__content',
372+
}),
373+
{
374+
...attrs,
375+
...dialogProps.value,
376+
ref: dialogHack,
377+
},
378+
slots
379+
),
329380
{
330-
...attrs,
331-
...dialogProps.value,
332-
},
333-
slots
381+
ref: dialogHack,
382+
}
334383
),
335384
]
336385
),
337386
]
338-
),
339-
])
387+
)
388+
)
340389
},
341390
})
342391

0 commit comments

Comments
 (0)