VList.mjs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import { createVNode as _createVNode, resolveDirective as _resolveDirective } from "vue";
  2. // Styles
  3. import "./VList.css";
  4. // Components
  5. import { VListChildren } from "./VListChildren.mjs"; // Composables
  6. import { createList } from "./list.mjs";
  7. import { makeBorderProps, useBorder } from "../../composables/border.mjs";
  8. import { useBackgroundColor } from "../../composables/color.mjs";
  9. import { makeComponentProps } from "../../composables/component.mjs";
  10. import { provideDefaults } from "../../composables/defaults.mjs";
  11. import { makeDensityProps, useDensity } from "../../composables/density.mjs";
  12. import { makeDimensionProps, useDimension } from "../../composables/dimensions.mjs";
  13. import { makeElevationProps, useElevation } from "../../composables/elevation.mjs";
  14. import { IconValue } from "../../composables/icons.mjs";
  15. import { makeItemsProps } from "../../composables/list-items.mjs";
  16. import { makeNestedProps, useNested } from "../../composables/nested/nested.mjs";
  17. import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs";
  18. import { makeTagProps } from "../../composables/tag.mjs";
  19. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
  20. import { makeVariantProps } from "../../composables/variant.mjs"; // Utilities
  21. import { computed, ref, shallowRef, toRef } from 'vue';
  22. import { EventProp, focusChild, genericComponent, getPropertyFromItem, omit, propsFactory, useRender } from "../../util/index.mjs"; // Types
  23. function isPrimitive(value) {
  24. return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
  25. }
  26. function transformItem(props, item) {
  27. const type = getPropertyFromItem(item, props.itemType, 'item');
  28. const title = isPrimitive(item) ? item : getPropertyFromItem(item, props.itemTitle);
  29. const value = getPropertyFromItem(item, props.itemValue, undefined);
  30. const children = getPropertyFromItem(item, props.itemChildren);
  31. const itemProps = props.itemProps === true ? omit(item, ['children']) : getPropertyFromItem(item, props.itemProps);
  32. const _props = {
  33. title,
  34. value,
  35. ...itemProps
  36. };
  37. return {
  38. type,
  39. title: _props.title,
  40. value: _props.value,
  41. props: _props,
  42. children: type === 'item' && children ? transformItems(props, children) : undefined,
  43. raw: item
  44. };
  45. }
  46. function transformItems(props, items) {
  47. const array = [];
  48. for (const item of items) {
  49. array.push(transformItem(props, item));
  50. }
  51. return array;
  52. }
  53. export function useListItems(props) {
  54. const items = computed(() => transformItems(props, props.items));
  55. return {
  56. items
  57. };
  58. }
  59. export const makeVListProps = propsFactory({
  60. baseColor: String,
  61. /* @deprecated */
  62. activeColor: String,
  63. activeClass: String,
  64. bgColor: String,
  65. disabled: Boolean,
  66. expandIcon: IconValue,
  67. collapseIcon: IconValue,
  68. lines: {
  69. type: [Boolean, String],
  70. default: 'one'
  71. },
  72. slim: Boolean,
  73. nav: Boolean,
  74. 'onClick:open': EventProp(),
  75. 'onClick:select': EventProp(),
  76. 'onUpdate:opened': EventProp(),
  77. ...makeNestedProps({
  78. selectStrategy: 'single-leaf',
  79. openStrategy: 'list'
  80. }),
  81. ...makeBorderProps(),
  82. ...makeComponentProps(),
  83. ...makeDensityProps(),
  84. ...makeDimensionProps(),
  85. ...makeElevationProps(),
  86. itemType: {
  87. type: String,
  88. default: 'type'
  89. },
  90. ...makeItemsProps(),
  91. ...makeRoundedProps(),
  92. ...makeTagProps(),
  93. ...makeThemeProps(),
  94. ...makeVariantProps({
  95. variant: 'text'
  96. })
  97. }, 'VList');
  98. export const VList = genericComponent()({
  99. name: 'VList',
  100. props: makeVListProps(),
  101. emits: {
  102. 'update:selected': value => true,
  103. 'update:activated': value => true,
  104. 'update:opened': value => true,
  105. 'click:open': value => true,
  106. 'click:activate': value => true,
  107. 'click:select': value => true
  108. },
  109. setup(props, _ref) {
  110. let {
  111. slots
  112. } = _ref;
  113. const {
  114. items
  115. } = useListItems(props);
  116. const {
  117. themeClasses
  118. } = provideTheme(props);
  119. const {
  120. backgroundColorClasses,
  121. backgroundColorStyles
  122. } = useBackgroundColor(toRef(props, 'bgColor'));
  123. const {
  124. borderClasses
  125. } = useBorder(props);
  126. const {
  127. densityClasses
  128. } = useDensity(props);
  129. const {
  130. dimensionStyles
  131. } = useDimension(props);
  132. const {
  133. elevationClasses
  134. } = useElevation(props);
  135. const {
  136. roundedClasses
  137. } = useRounded(props);
  138. const {
  139. children,
  140. open,
  141. parents,
  142. select,
  143. getPath
  144. } = useNested(props);
  145. const lineClasses = computed(() => props.lines ? `v-list--${props.lines}-line` : undefined);
  146. const activeColor = toRef(props, 'activeColor');
  147. const baseColor = toRef(props, 'baseColor');
  148. const color = toRef(props, 'color');
  149. createList();
  150. provideDefaults({
  151. VListGroup: {
  152. activeColor,
  153. baseColor,
  154. color,
  155. expandIcon: toRef(props, 'expandIcon'),
  156. collapseIcon: toRef(props, 'collapseIcon')
  157. },
  158. VListItem: {
  159. activeClass: toRef(props, 'activeClass'),
  160. activeColor,
  161. baseColor,
  162. color,
  163. density: toRef(props, 'density'),
  164. disabled: toRef(props, 'disabled'),
  165. lines: toRef(props, 'lines'),
  166. nav: toRef(props, 'nav'),
  167. slim: toRef(props, 'slim'),
  168. variant: toRef(props, 'variant')
  169. }
  170. });
  171. const isFocused = shallowRef(false);
  172. const contentRef = ref();
  173. function onFocusin(e) {
  174. isFocused.value = true;
  175. }
  176. function onFocusout(e) {
  177. isFocused.value = false;
  178. }
  179. function onFocus(e) {
  180. if (!isFocused.value && !(e.relatedTarget && contentRef.value?.contains(e.relatedTarget))) focus();
  181. }
  182. function onKeydown(e) {
  183. const target = e.target;
  184. if (!contentRef.value || ['INPUT', 'TEXTAREA'].includes(target.tagName)) return;
  185. if (e.key === 'ArrowDown') {
  186. focus('next');
  187. } else if (e.key === 'ArrowUp') {
  188. focus('prev');
  189. } else if (e.key === 'Home') {
  190. focus('first');
  191. } else if (e.key === 'End') {
  192. focus('last');
  193. } else {
  194. return;
  195. }
  196. e.preventDefault();
  197. }
  198. function onMousedown(e) {
  199. isFocused.value = true;
  200. }
  201. function focus(location) {
  202. if (contentRef.value) {
  203. return focusChild(contentRef.value, location);
  204. }
  205. }
  206. useRender(() => {
  207. return _createVNode(props.tag, {
  208. "ref": contentRef,
  209. "class": ['v-list', {
  210. 'v-list--disabled': props.disabled,
  211. 'v-list--nav': props.nav,
  212. 'v-list--slim': props.slim
  213. }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, props.class],
  214. "style": [backgroundColorStyles.value, dimensionStyles.value, props.style],
  215. "tabindex": props.disabled || isFocused.value ? -1 : 0,
  216. "role": "listbox",
  217. "aria-activedescendant": undefined,
  218. "onFocusin": onFocusin,
  219. "onFocusout": onFocusout,
  220. "onFocus": onFocus,
  221. "onKeydown": onKeydown,
  222. "onMousedown": onMousedown
  223. }, {
  224. default: () => [_createVNode(VListChildren, {
  225. "items": items.value,
  226. "returnObject": props.returnObject
  227. }, slots)]
  228. });
  229. });
  230. return {
  231. open,
  232. select,
  233. focus,
  234. children,
  235. parents,
  236. getPath
  237. };
  238. }
  239. });
  240. //# sourceMappingURL=VList.mjs.map