quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
209 lines (167 loc) • 5.25 kB
JavaScript
import { h, computed, getCurrentInstance } from 'vue'
import QIcon from '../icon/QIcon.js'
import Ripple from '../../directives/Ripple.js'
import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
import useSize, { useSizeProps } from '../../composables/private/use-size.js'
import { createComponent } from '../../utils/private/create.js'
import { stopAndPrevent } from '../../utils/event.js'
import { hMergeSlotSafely, hDir } from '../../utils/private/render.js'
export const defaultSizes = {
xs: 8,
sm: 10,
md: 14,
lg: 20,
xl: 24
}
export default createComponent({
name: 'QChip',
props: {
...useDarkProps,
...useSizeProps,
dense: Boolean,
icon: String,
iconRight: String,
iconRemove: String,
iconSelected: String,
label: [ String, Number ],
color: String,
textColor: String,
modelValue: {
type: Boolean,
default: true
},
selected: {
type: Boolean,
default: null
},
square: Boolean,
outline: Boolean,
clickable: Boolean,
removable: Boolean,
removeAriaLabel: String,
tabindex: [ String, Number ],
disable: Boolean,
ripple: {
type: [ Boolean, Object ],
default: true
}
},
emits: [ 'update:modelValue', 'update:selected', 'remove', 'click' ],
setup (props, { slots, emit }) {
const { proxy: { $q } } = getCurrentInstance()
const isDark = useDark(props, $q)
const sizeStyle = useSize(props, defaultSizes)
const hasLeftIcon = computed(() => props.selected === true || props.icon !== void 0)
const leftIcon = computed(() => (
props.selected === true
? props.iconSelected || $q.iconSet.chip.selected
: props.icon
))
const removeIcon = computed(() => props.iconRemove || $q.iconSet.chip.remove)
const isClickable = computed(() =>
props.disable === false
&& (props.clickable === true || props.selected !== null)
)
const classes = computed(() => {
const text = props.outline === true
? props.color || props.textColor
: props.textColor
return 'q-chip row inline no-wrap items-center'
+ (props.outline === false && props.color !== void 0 ? ` bg-${ props.color }` : '')
+ (text ? ` text-${ text } q-chip--colored` : '')
+ (props.disable === true ? ' disabled' : '')
+ (props.dense === true ? ' q-chip--dense' : '')
+ (props.outline === true ? ' q-chip--outline' : '')
+ (props.selected === true ? ' q-chip--selected' : '')
+ (isClickable.value === true ? ' q-chip--clickable cursor-pointer non-selectable q-hoverable' : '')
+ (props.square === true ? ' q-chip--square' : '')
+ (isDark.value === true ? ' q-chip--dark q-dark' : '')
})
const attributes = computed(() => {
const chip = props.disable === true
? { tabindex: -1, 'aria-disabled': 'true' }
: { tabindex: props.tabindex || 0 }
const remove = {
...chip,
role: 'button',
'aria-hidden': 'false',
'aria-label': props.removeAriaLabel || $q.lang.label.remove
}
return { chip, remove }
})
function onKeyup (e) {
e.keyCode === 13 /* ENTER */ && onClick(e)
}
function onClick (e) {
if (!props.disable) {
emit('update:selected', !props.selected)
emit('click', e)
}
}
function onRemove (e) {
if (e.keyCode === void 0 || e.keyCode === 13) {
stopAndPrevent(e)
if (props.disable === false) {
emit('update:modelValue', false)
emit('remove')
}
}
}
function getContent () {
const child = []
isClickable.value === true && child.push(
h('div', { class: 'q-focus-helper' })
)
hasLeftIcon.value === true && child.push(
h(QIcon, {
class: 'q-chip__icon q-chip__icon--left',
name: leftIcon.value
})
)
const label = props.label !== void 0
? [ h('div', { class: 'ellipsis' }, [ props.label ]) ]
: void 0
child.push(
h('div', {
class: 'q-chip__content col row no-wrap items-center q-anchor--skip'
}, hMergeSlotSafely(slots.default, label))
)
props.iconRight && child.push(
h(QIcon, {
class: 'q-chip__icon q-chip__icon--right',
name: props.iconRight
})
)
props.removable === true && child.push(
h(QIcon, {
class: 'q-chip__icon q-chip__icon--remove cursor-pointer',
name: removeIcon.value,
...attributes.value.remove,
onClick: onRemove,
onKeyup: onRemove
})
)
return child
}
return () => {
if (props.modelValue === false) { return }
const data = {
class: classes.value,
style: sizeStyle.value
}
isClickable.value === true && Object.assign(
data,
attributes.value.chip,
{ onClick, onKeyup }
)
return hDir(
'div',
data,
getContent(),
'ripple',
props.ripple !== false && props.disable !== true,
() => [ [ Ripple, props.ripple ] ]
)
}
}
})