VChip.mjs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import { mergeProps as _mergeProps, Fragment as _Fragment, withDirectives as _withDirectives, vShow as _vShow, resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
  2. /* eslint-disable complexity */
  3. // Styles
  4. import "./VChip.css";
  5. // Components
  6. import { VExpandXTransition } from "../transitions/index.mjs";
  7. import { VAvatar } from "../VAvatar/index.mjs";
  8. import { VChipGroupSymbol } from "../VChipGroup/VChipGroup.mjs";
  9. import { VDefaultsProvider } from "../VDefaultsProvider/index.mjs";
  10. import { VIcon } from "../VIcon/index.mjs"; // Composables
  11. import { makeBorderProps, useBorder } from "../../composables/border.mjs";
  12. import { makeComponentProps } from "../../composables/component.mjs";
  13. import { makeDensityProps, useDensity } from "../../composables/density.mjs";
  14. import { makeElevationProps, useElevation } from "../../composables/elevation.mjs";
  15. import { makeGroupItemProps, useGroupItem } from "../../composables/group.mjs";
  16. import { IconValue } from "../../composables/icons.mjs";
  17. import { useLocale } from "../../composables/locale.mjs";
  18. import { useProxiedModel } from "../../composables/proxiedModel.mjs";
  19. import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs";
  20. import { makeRouterProps, useLink } from "../../composables/router.mjs";
  21. import { makeSizeProps, useSize } from "../../composables/size.mjs";
  22. import { makeTagProps } from "../../composables/tag.mjs";
  23. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
  24. import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.mjs"; // Directives
  25. import { Ripple } from "../../directives/ripple/index.mjs"; // Utilities
  26. import { computed } from 'vue';
  27. import { EventProp, genericComponent, propsFactory } from "../../util/index.mjs"; // Types
  28. export const makeVChipProps = propsFactory({
  29. activeClass: String,
  30. appendAvatar: String,
  31. appendIcon: IconValue,
  32. closable: Boolean,
  33. closeIcon: {
  34. type: IconValue,
  35. default: '$delete'
  36. },
  37. closeLabel: {
  38. type: String,
  39. default: '$vuetify.close'
  40. },
  41. draggable: Boolean,
  42. filter: Boolean,
  43. filterIcon: {
  44. type: IconValue,
  45. default: '$complete'
  46. },
  47. label: Boolean,
  48. link: {
  49. type: Boolean,
  50. default: undefined
  51. },
  52. pill: Boolean,
  53. prependAvatar: String,
  54. prependIcon: IconValue,
  55. ripple: {
  56. type: [Boolean, Object],
  57. default: true
  58. },
  59. text: String,
  60. modelValue: {
  61. type: Boolean,
  62. default: true
  63. },
  64. onClick: EventProp(),
  65. onClickOnce: EventProp(),
  66. ...makeBorderProps(),
  67. ...makeComponentProps(),
  68. ...makeDensityProps(),
  69. ...makeElevationProps(),
  70. ...makeGroupItemProps(),
  71. ...makeRoundedProps(),
  72. ...makeRouterProps(),
  73. ...makeSizeProps(),
  74. ...makeTagProps({
  75. tag: 'span'
  76. }),
  77. ...makeThemeProps(),
  78. ...makeVariantProps({
  79. variant: 'tonal'
  80. })
  81. }, 'VChip');
  82. export const VChip = genericComponent()({
  83. name: 'VChip',
  84. directives: {
  85. Ripple
  86. },
  87. props: makeVChipProps(),
  88. emits: {
  89. 'click:close': e => true,
  90. 'update:modelValue': value => true,
  91. 'group:selected': val => true,
  92. click: e => true
  93. },
  94. setup(props, _ref) {
  95. let {
  96. attrs,
  97. emit,
  98. slots
  99. } = _ref;
  100. const {
  101. t
  102. } = useLocale();
  103. const {
  104. borderClasses
  105. } = useBorder(props);
  106. const {
  107. colorClasses,
  108. colorStyles,
  109. variantClasses
  110. } = useVariant(props);
  111. const {
  112. densityClasses
  113. } = useDensity(props);
  114. const {
  115. elevationClasses
  116. } = useElevation(props);
  117. const {
  118. roundedClasses
  119. } = useRounded(props);
  120. const {
  121. sizeClasses
  122. } = useSize(props);
  123. const {
  124. themeClasses
  125. } = provideTheme(props);
  126. const isActive = useProxiedModel(props, 'modelValue');
  127. const group = useGroupItem(props, VChipGroupSymbol, false);
  128. const link = useLink(props, attrs);
  129. const isLink = computed(() => props.link !== false && link.isLink.value);
  130. const isClickable = computed(() => !props.disabled && props.link !== false && (!!group || props.link || link.isClickable.value));
  131. const closeProps = computed(() => ({
  132. 'aria-label': t(props.closeLabel),
  133. onClick(e) {
  134. e.preventDefault();
  135. e.stopPropagation();
  136. isActive.value = false;
  137. emit('click:close', e);
  138. }
  139. }));
  140. function onClick(e) {
  141. emit('click', e);
  142. if (!isClickable.value) return;
  143. link.navigate?.(e);
  144. group?.toggle();
  145. }
  146. function onKeyDown(e) {
  147. if (e.key === 'Enter' || e.key === ' ') {
  148. e.preventDefault();
  149. onClick(e);
  150. }
  151. }
  152. return () => {
  153. const Tag = link.isLink.value ? 'a' : props.tag;
  154. const hasAppendMedia = !!(props.appendIcon || props.appendAvatar);
  155. const hasAppend = !!(hasAppendMedia || slots.append);
  156. const hasClose = !!(slots.close || props.closable);
  157. const hasFilter = !!(slots.filter || props.filter) && group;
  158. const hasPrependMedia = !!(props.prependIcon || props.prependAvatar);
  159. const hasPrepend = !!(hasPrependMedia || slots.prepend);
  160. const hasColor = !group || group.isSelected.value;
  161. return isActive.value && _withDirectives(_createVNode(Tag, _mergeProps({
  162. "class": ['v-chip', {
  163. 'v-chip--disabled': props.disabled,
  164. 'v-chip--label': props.label,
  165. 'v-chip--link': isClickable.value,
  166. 'v-chip--filter': hasFilter,
  167. 'v-chip--pill': props.pill,
  168. [`${props.activeClass}`]: props.activeClass && link.isActive?.value
  169. }, themeClasses.value, borderClasses.value, hasColor ? colorClasses.value : undefined, densityClasses.value, elevationClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, group?.selectedClass.value, props.class],
  170. "style": [hasColor ? colorStyles.value : undefined, props.style],
  171. "disabled": props.disabled || undefined,
  172. "draggable": props.draggable,
  173. "tabindex": isClickable.value ? 0 : undefined,
  174. "onClick": onClick,
  175. "onKeydown": isClickable.value && !isLink.value && onKeyDown
  176. }, link.linkProps), {
  177. default: () => [genOverlays(isClickable.value, 'v-chip'), hasFilter && _createVNode(VExpandXTransition, {
  178. "key": "filter"
  179. }, {
  180. default: () => [_withDirectives(_createVNode("div", {
  181. "class": "v-chip__filter"
  182. }, [!slots.filter ? _createVNode(VIcon, {
  183. "key": "filter-icon",
  184. "icon": props.filterIcon
  185. }, null) : _createVNode(VDefaultsProvider, {
  186. "key": "filter-defaults",
  187. "disabled": !props.filterIcon,
  188. "defaults": {
  189. VIcon: {
  190. icon: props.filterIcon
  191. }
  192. }
  193. }, slots.filter)]), [[_vShow, group.isSelected.value]])]
  194. }), hasPrepend && _createVNode("div", {
  195. "key": "prepend",
  196. "class": "v-chip__prepend"
  197. }, [!slots.prepend ? _createVNode(_Fragment, null, [props.prependIcon && _createVNode(VIcon, {
  198. "key": "prepend-icon",
  199. "icon": props.prependIcon,
  200. "start": true
  201. }, null), props.prependAvatar && _createVNode(VAvatar, {
  202. "key": "prepend-avatar",
  203. "image": props.prependAvatar,
  204. "start": true
  205. }, null)]) : _createVNode(VDefaultsProvider, {
  206. "key": "prepend-defaults",
  207. "disabled": !hasPrependMedia,
  208. "defaults": {
  209. VAvatar: {
  210. image: props.prependAvatar,
  211. start: true
  212. },
  213. VIcon: {
  214. icon: props.prependIcon,
  215. start: true
  216. }
  217. }
  218. }, slots.prepend)]), _createVNode("div", {
  219. "class": "v-chip__content",
  220. "data-no-activator": ""
  221. }, [slots.default?.({
  222. isSelected: group?.isSelected.value,
  223. selectedClass: group?.selectedClass.value,
  224. select: group?.select,
  225. toggle: group?.toggle,
  226. value: group?.value.value,
  227. disabled: props.disabled
  228. }) ?? props.text]), hasAppend && _createVNode("div", {
  229. "key": "append",
  230. "class": "v-chip__append"
  231. }, [!slots.append ? _createVNode(_Fragment, null, [props.appendIcon && _createVNode(VIcon, {
  232. "key": "append-icon",
  233. "end": true,
  234. "icon": props.appendIcon
  235. }, null), props.appendAvatar && _createVNode(VAvatar, {
  236. "key": "append-avatar",
  237. "end": true,
  238. "image": props.appendAvatar
  239. }, null)]) : _createVNode(VDefaultsProvider, {
  240. "key": "append-defaults",
  241. "disabled": !hasAppendMedia,
  242. "defaults": {
  243. VAvatar: {
  244. end: true,
  245. image: props.appendAvatar
  246. },
  247. VIcon: {
  248. end: true,
  249. icon: props.appendIcon
  250. }
  251. }
  252. }, slots.append)]), hasClose && _createVNode("button", _mergeProps({
  253. "key": "close",
  254. "class": "v-chip__close",
  255. "type": "button",
  256. "data-testid": "close-chip"
  257. }, closeProps.value), [!slots.close ? _createVNode(VIcon, {
  258. "key": "close-icon",
  259. "icon": props.closeIcon,
  260. "size": "x-small"
  261. }, null) : _createVNode(VDefaultsProvider, {
  262. "key": "close-defaults",
  263. "defaults": {
  264. VIcon: {
  265. icon: props.closeIcon,
  266. size: 'x-small'
  267. }
  268. }
  269. }, slots.close)])]
  270. }), [[_resolveDirective("ripple"), isClickable.value && props.ripple, null]]);
  271. };
  272. }
  273. });
  274. //# sourceMappingURL=VChip.mjs.map