VList.mjs 6.5 KB

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