quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
168 lines (137 loc) • 4.19 kB
JavaScript
import { h, ref, computed, getCurrentInstance } from 'vue'
import useDark, {
useDarkProps
} from '../../composables/private.use-dark/use-dark.js'
import useRouterLink, {
useRouterLinkProps
} from '../../composables/private.use-router-link/use-router-link.js'
import { createComponent } from '../../utils/private.create/create.js'
import { hUniqueSlot } from '../../utils/private.render/render.js'
import { stopAndPrevent } from '../../utils/event/event.js'
import { isKeyCode } from '../../utils/private.keyboard/key-composition.js'
export default createComponent({
name: 'QItem',
props: {
...useDarkProps,
...useRouterLinkProps,
tag: {
type: String,
default: 'div'
},
active: {
type: Boolean,
default: null
},
clickable: Boolean,
dense: Boolean,
insetLevel: Number,
tabindex: [String, Number],
focused: Boolean,
manualFocus: Boolean
},
emits: ['click', 'keyup'],
setup(props, { slots, emit }) {
const {
proxy: { $q }
} = getCurrentInstance()
const isDark = useDark(props, $q)
const { hasLink, linkAttrs, linkClass, linkTag, navigateOnClick } =
useRouterLink()
const rootRef = ref(null)
const blurTargetRef = ref(null)
const isActionable = computed(
() =>
props.clickable === true ||
hasLink.value === true ||
props.tag === 'label'
)
const isClickable = computed(
() => props.disable !== true && isActionable.value === true
)
const classes = computed(
() =>
'q-item q-item-type row no-wrap' +
(props.dense === true ? ' q-item--dense' : '') +
(isDark.value === true ? ' q-item--dark' : '') +
(hasLink.value === true && props.active === null
? linkClass.value
: props.active === true
? ` q-item--active${props.activeClass !== void 0 ? ` ${props.activeClass}` : ''}`
: '') +
(props.disable === true ? ' disabled' : '') +
(isClickable.value === true
? ' q-item--clickable q-link cursor-pointer ' +
(props.manualFocus === true
? 'q-manual-focusable'
: 'q-focusable q-hoverable') +
(props.focused === true ? ' q-manual-focusable--focused' : '')
: '')
)
const style = computed(() => {
if (props.insetLevel === void 0) {
return null
}
const dir = $q.lang.rtl === true ? 'Right' : 'Left'
return {
['padding' + dir]: 16 + props.insetLevel * 56 + 'px'
}
})
function onClick(e) {
if (isClickable.value === true) {
if (blurTargetRef.value !== null && e.qAvoidFocus !== true) {
if (
e.qKeyEvent !== true &&
document.activeElement === rootRef.value
) {
blurTargetRef.value.focus()
} else if (document.activeElement === blurTargetRef.value) {
rootRef.value.focus()
}
}
navigateOnClick(e)
}
}
function onKeyup(e) {
if (isClickable.value === true && isKeyCode(e, [13, 32]) === true) {
stopAndPrevent(e)
// for ripple
e.qKeyEvent = true
// for click trigger
const evt = new MouseEvent('click', e)
evt.qKeyEvent = true
rootRef.value.dispatchEvent(evt)
}
emit('keyup', e)
}
function getContent() {
const child = hUniqueSlot(slots.default, [])
if (isClickable.value === true) {
child.unshift(
h('div', {
class: 'q-focus-helper',
tabindex: -1,
ref: blurTargetRef
})
)
}
return child
}
return () => {
const data = {
ref: rootRef,
class: classes.value,
style: style.value,
role: 'listitem',
onClick,
onKeyup
}
if (isClickable.value === true) {
data.tabindex = props.tabindex || '0'
Object.assign(data, linkAttrs.value)
} else if (isActionable.value === true) {
data['aria-disabled'] = 'true'
}
return h(linkTag.value, data, getContent())
}
}
})