Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(toogle-group): tabindex #345

Merged
merged 3 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions packages/components/checkbox/src/checkbox.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createProvideScope } from '@oku-ui/provide'
import type { PropType, Ref } from 'vue'
import { computed, defineComponent, h, ref, toRefs, useModel, watchEffect } from 'vue'
import { computed, defineComponent, h, mergeProps, reactive, ref, toRefs, useModel, watchEffect } from 'vue'

import { composeEventHandlers } from '@oku-ui/utils'
import { useComposedRefs, useControllable, useForwardRef } from '@oku-ui/use-composable'
Expand Down Expand Up @@ -103,12 +103,15 @@ const Checkbox = defineComponent({
emits: checkboxProps.emits,
setup(props, { attrs, slots, emit }) {
const {
modelValue: _modelValue,
scopeOkuCheckbox,
checked: checkedProp,
defaultChecked,
required,
disabled,
name,
value,
...checkboxProps
} = toRefs(props)

const buttonRef = ref<HTMLButtonElement | null>(null)
Expand Down Expand Up @@ -154,23 +157,25 @@ const Checkbox = defineComponent({
})

CheckboxProvider({
scope: props.scopeOkuCheckbox,
scope: scopeOkuCheckbox.value,
state,
disabled,
})

const reactiveCheckboxProps = reactive(checkboxProps)

const originalReturn = () =>
[h(Primitive.button, {
'type': 'button',
'role': 'checkbox',
'aria-checked': isIndeterminate(state.value) ? 'mixed' : state.value as any,
'aria-checked': computed(() => isIndeterminate(state.value) ? 'mixed' : state.value).value as any,
'aria-required': required.value,
'data-state': computed(() => getState(state.value)).value,
'data-disabled': disabled.value ? '' : undefined,
'disabled': disabled.value,
'value': value.value,
'asChild': props.asChild,
...checkboxAttrs,
...mergeProps(checkboxAttrs, reactiveCheckboxProps),
'ref': composedRefs,
'onKeyDown': composeEventHandlers<KeyboardEvent>((e) => {
emit('keydown', e)
Expand Down
20 changes: 2 additions & 18 deletions packages/components/roving-focus/src/RovingFocusGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createProvideScope } from '@oku-ui/provide'
import type { CollectionPropsType } from '@oku-ui/collection'
import { createCollection } from '@oku-ui/collection'
import type { Ref } from 'vue'
import { defineComponent, h, mergeProps, toRefs } from 'vue'
import { defineComponent, h, mergeProps } from 'vue'
import { useForwardRef } from '@oku-ui/use-composable'
import { primitiveProps } from '@oku-ui/primitive'
import { OkuRovingFocusGroupImpl, rovingFocusGroupImplProps } from './RovingFocusGroupImpl'
Expand Down Expand Up @@ -90,16 +90,6 @@ const rovingFocusGroup = defineComponent({
},
emits: rovingFocusGroupProps.emits,
setup(props, { slots, attrs }) {
const {
currentTabStopId,
dir,
loop,
orientation,
defaultCurrentTabStopId,
asChild,
...rest
} = toRefs(props)

const forwardedRef = useForwardRef()
return () => {
return h(CollectionProvider, {
Expand All @@ -109,13 +99,7 @@ const rovingFocusGroup = defineComponent({
scope: props.scopeOkuRovingFocusGroup,
}, {
default: () => h(OkuRovingFocusGroupImpl, {
...mergeProps(rest, attrs),
asChild: asChild.value,
currentTabStopId: currentTabStopId?.value,
defaultCurrentTabStopId: defaultCurrentTabStopId?.value,
dir: dir?.value,
loop: loop?.value,
orientation: orientation?.value,
...mergeProps(attrs, props),
ref: forwardedRef,
}, slots),
}),
Expand Down
31 changes: 16 additions & 15 deletions packages/components/roving-focus/src/RovingFocusGroupImpl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ComputedRef, PropType } from 'vue'
import { computed, defineComponent, h, mergeProps, ref, toRefs, unref, watchEffect } from 'vue'
import { useCallbackRef, useComposedRefs, useControllable, useForwardRef } from '@oku-ui/use-composable'
import { computed, defineComponent, h, mergeProps, reactive, ref, toRefs, watchEffect } from 'vue'
import { useComposedRefs, useControllable, useForwardRef } from '@oku-ui/use-composable'

import type { OkuElement } from '@oku-ui/primitive'

Expand Down Expand Up @@ -60,17 +60,14 @@ const RovingFocusGroupImpl = defineComponent({
},
emits: rovingFocusGroupImplProps.emits,
setup(props, { attrs, slots, emit }) {
const _attrs = attrs as Omit<RovingFocusGroupImplNaviteElement, 'dir'>
const {
scopeOkuRovingFocusGroup,
orientation,
loop,
dir,
currentTabStopId: currentTabStopIdProp,
defaultCurrentTabStopId,
onEntryFocus,
asChild,
scopeOkuRovingFocusGroup,
dir,
...propsData
...groupProps
} = toRefs(props)

const buttonRef = ref<HTMLDivElement | null>(null)
Expand All @@ -87,16 +84,19 @@ const RovingFocusGroupImpl = defineComponent({
})

const isTabbingBackOut = ref(false)
const handleEntryFocus = useCallbackRef(onEntryFocus?.value || undefined)
const getItems = useCollection(scopeOkuRovingFocusGroup.value)
const isClickFocusRef = ref(false)
const focusableItemsCount = ref(0)

watchEffect(() => {
const node = buttonRef.value
if (node) {
node.addEventListener(ENTRY_FOCUS, handleEntryFocus.value)
return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus.value)
node.addEventListener(ENTRY_FOCUS, (event) => {
emit('entryFocus', event)
})
return () => node.removeEventListener(ENTRY_FOCUS, (event) => {
emit('entryFocus', event)
})
}
})

Expand All @@ -105,7 +105,7 @@ const RovingFocusGroupImpl = defineComponent({
orientation,
dir,
loop,
currentTabStopId: currentTabStopId || null,
currentTabStopId,
onItemFocus: (tabStopId: string) => {
updateCurrentTabStopId(tabStopId)
},
Expand All @@ -120,17 +120,18 @@ const RovingFocusGroupImpl = defineComponent({
},
})

const _reactiveProupProps = reactive(groupProps)

return () => {
return h(Primitive.div, {
'tabindex': isTabbingBackOut.value || focusableItemsCount.value === 0 ? -1 : 0,
'data-orientation': orientation?.value,
...unref(mergeProps(propsData, _attrs)),
...mergeProps(attrs, _reactiveProupProps),
'ref': composedRefs,
'style': {
outline: 'none',
..._attrs.style as any,
...attrs.style as any,
},
'asChild': asChild.value,
'onMousedown': composeEventHandlers<MouseEvent>((e) => {
emit('mousedown', e)
}, () => {
Expand Down
13 changes: 5 additions & 8 deletions packages/components/roving-focus/src/RovingFocusGroupItem.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, defineComponent, h, nextTick, toRefs, watchEffect } from 'vue'
import { computed, defineComponent, h, mergeProps, nextTick, reactive, toRefs, watchEffect } from 'vue'
import { useForwardRef, useId } from '@oku-ui/use-composable'

import { Primitive, primitiveProps } from '@oku-ui/primitive'
Expand Down Expand Up @@ -63,15 +63,13 @@ const rovingFocusGroupItem = defineComponent({
},
emits: rovingFocusItemProps.emits,
setup(props, { attrs, slots, emit }) {
const _attrs = attrs as any
const {
scopeOkuRovingFocusGroup,
focusable,
active,
tabStopId,
scopeOkuRovingFocusGroup,
asChild,
...itemProps
} = toRefs(props)
const attrsItems = _attrs

const autoId = useId()
const id = computed(() => tabStopId.value || autoId)
Expand All @@ -91,7 +89,7 @@ const rovingFocusGroupItem = defineComponent({
})
})
})

const reactiveItemProps = reactive(itemProps)
return () => {
return h(CollectionItemSlot, {
id: id.value,
Expand All @@ -102,10 +100,9 @@ const rovingFocusGroupItem = defineComponent({
default: () => {
return h(Primitive.span, {
'tabindex': isCurrentTabStop.value ? 0 : -1,
...attrsItems,
...mergeProps(attrs, reactiveItemProps),
'data-orientation': inject.orientation?.value,
'ref': forwardedRef,
'asChild': asChild.value,
'onMousedown':
composeEventHandlers<MouseEvent>((e) => {
emit('mousedown', e)
Expand Down
86 changes: 76 additions & 10 deletions packages/components/toggle-group/src/ToggleGroup.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { primitiveProps } from '@oku-ui/primitive'
import { defineComponent, h, mergeProps } from 'vue'
import type { Ref } from 'vue'
import { defineComponent, h, mergeProps, reactive } from 'vue'
import type { PropType, Ref } from 'vue'
import { useForwardRef } from '@oku-ui/use-composable'

import { createProvideScope } from '@oku-ui/provide'
import { createRovingFocusGroupScope } from '@oku-ui/roving-focus'

import { scopeToggleGroupProps } from './utils'

import type { ToggleGroupImplElement, ToggleGroupImplNaviteElement } from './ToggleGroupImpl'
import type { ToggleGroupVariantEmits, ToggleGroupVariantProps } from './ToggleGroupVariant'
import { OkuToggleGroupVariant, toggleGroupVariantProps } from './ToggleGroupVariant'
import { toggleGroupImplProps } from './ToggleGroupImpl'
import type { ToggleGroupImplElement, ToggleGroupImplNaviteElement, ToggleGroupImplProps } from './ToggleGroupImpl'
import { OkuToggleGroupImplSingle } from './ToggleGroupImplSingle'
import { OkuToggleGroupImplMultiple } from './ToggleGroupImplMultiple'

export const TOGGLE_GROUP_NAME = 'OkuToggleGroup'

Expand All @@ -19,7 +20,7 @@ export const [createToggleGroupProvide, createToggleGroupScope] = createProvideS
])

type ToggleGroupValueProvide = {
type: Ref<'single' | 'multiple'>
type: 'single' | 'multiple'
value: Ref<string[]>
onItemActivate(value: string): void
onItemDeactivate(value: string): void
Expand All @@ -44,6 +45,52 @@ export type ToggleGroupEmits = ToggleGroupVariantEmits
export type ToggleGroupElement = ToggleGroupImplElement
export type ToggleGroupNaviteElement = ToggleGroupImplNaviteElement

export interface ToggleGroupVariantProps extends ToggleGroupImplProps {
type: 'single' | 'multiple'
/**
* The controlled stateful value of the item that is pressed.
*/
value?: string | string[]
/**
* The value of the item that is pressed when initially rendered. Use
* `defaultValue` if you do not need to control the state of a toggle group.
*/
defaultValue?: string | string[]
}

export type ToggleGroupVariantEmits = {
/**
* The callback that fires when the value of the toggle group changes.
*/
'valueChange': [value: string | string[]]
}

export const toggleGroupVariantProps = {
props: {
type: {
type: [String] as PropType<'single' | 'multiple'>,
required: true,
},
modelValue: {
type: [String, Array] as PropType<string | string[] | undefined>,
default: undefined,
},
value: {
type: [String, Array] as PropType<string | string[] | undefined>,
default: undefined,
},
defaultValue: {
type: [String, Array] as PropType<string | string[] | undefined>,
default: undefined,
},
...toggleGroupImplProps.props,
},
emits: {
// eslint-disable-next-line unused-imports/no-unused-vars
valueChange: (value: string | string[]) => true,
},
}

export const toggleGroupProps = {
props: {
...toggleGroupVariantProps.props,
Expand All @@ -55,6 +102,10 @@ export const toggleGroupProps = {

const toggleGroup = defineComponent({
name: TOGGLE_GROUP_NAME,
components: {
OkuToggleGroupImplSingle,
OkuToggleGroupImplMultiple,
},
inheritAttrs: false,
props: {
...toggleGroupProps.props,
Expand All @@ -63,12 +114,27 @@ const toggleGroup = defineComponent({
},
emits: toggleGroupProps.emits,
setup(props, { slots, attrs }) {
const { type, ...toggleGroupProps } = props

const forwardedRef = useForwardRef()
return () => {
return h(OkuToggleGroupVariant, {
...mergeProps(attrs, props),
ref: forwardedRef,
}, slots)
if (type === 'single') {
const singleProps = reactive(toggleGroupProps)
return h(OkuToggleGroupImplSingle, {
...mergeProps(attrs, singleProps),
ref: forwardedRef,
}, slots)
}

if (type === 'multiple') {
const multipleProps = reactive(toggleGroupProps)
return h(OkuToggleGroupImplMultiple, {
...mergeProps(attrs, multipleProps),
ref: forwardedRef,
}, slots)
}

throw new Error(`Missing prop \`type\` expected on \`${TOGGLE_GROUP_NAME}\``)
}
},
})
Expand Down
Loading