VTreeview.mjs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { createVNode as _createVNode, mergeProps as _mergeProps, resolveDirective as _resolveDirective } from "vue";
  2. // Components
  3. import { makeVTreeviewChildrenProps, VTreeviewChildren } from "./VTreeviewChildren.mjs";
  4. import { makeVListProps, useListItems, VList } from "../../components/VList/VList.mjs"; // Composables
  5. import { provideDefaults } from "../../composables/defaults.mjs";
  6. import { makeFilterProps, useFilter } from "../../composables/filter.mjs";
  7. import { useProxiedModel } from "../../composables/proxiedModel.mjs"; // Utilities
  8. import { computed, provide, ref, toRaw, toRef } from 'vue';
  9. import { genericComponent, omit, propsFactory, useRender } from "../../util/index.mjs"; // Types
  10. import { VTreeviewSymbol } from "./shared.mjs";
  11. function flatten(items) {
  12. let flat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  13. for (const item of items) {
  14. flat.push(item);
  15. if (item.children) flatten(item.children, flat);
  16. }
  17. return flat;
  18. }
  19. export const makeVTreeviewProps = propsFactory({
  20. openAll: Boolean,
  21. search: String,
  22. ...makeFilterProps({
  23. filterKeys: ['title']
  24. }),
  25. ...makeVTreeviewChildrenProps(),
  26. ...omit(makeVListProps({
  27. collapseIcon: '$treeviewCollapse',
  28. expandIcon: '$treeviewExpand',
  29. slim: true
  30. }), ['itemType', 'nav', 'openStrategy']),
  31. modelValue: {
  32. type: Array,
  33. default: () => []
  34. }
  35. }, 'VTreeview');
  36. export const VTreeview = genericComponent()({
  37. name: 'VTreeview',
  38. props: makeVTreeviewProps(),
  39. emits: {
  40. 'update:opened': val => true,
  41. 'update:activated': val => true,
  42. 'update:selected': val => true,
  43. 'update:modelValue': val => true,
  44. 'click:open': value => true,
  45. 'click:select': value => true
  46. },
  47. setup(props, _ref) {
  48. let {
  49. slots
  50. } = _ref;
  51. const {
  52. items
  53. } = useListItems(props);
  54. const activeColor = toRef(props, 'activeColor');
  55. const baseColor = toRef(props, 'baseColor');
  56. const color = toRef(props, 'color');
  57. const activated = useProxiedModel(props, 'activated');
  58. const model = useProxiedModel(props, 'modelValue');
  59. const _selected = useProxiedModel(props, 'selected', props.modelValue);
  60. const selected = computed({
  61. get: () => _selected.value,
  62. set(val) {
  63. _selected.value = val;
  64. model.value = val;
  65. }
  66. });
  67. const vListRef = ref();
  68. const opened = computed(() => props.openAll ? openAll(items.value) : props.opened);
  69. const flatItems = computed(() => flatten(items.value));
  70. const search = toRef(props, 'search');
  71. const {
  72. filteredItems
  73. } = useFilter(props, flatItems, search);
  74. const visibleIds = computed(() => {
  75. if (!search.value) return null;
  76. const getPath = vListRef.value?.getPath;
  77. if (!getPath) return null;
  78. return new Set(filteredItems.value.flatMap(item => {
  79. const itemVal = props.returnObject ? item.raw : item.props.value;
  80. return [...getPath(itemVal), ...getChildren(itemVal)].map(toRaw);
  81. }));
  82. });
  83. function getChildren(id) {
  84. const arr = [];
  85. const queue = (vListRef.value?.children.get(id) ?? []).slice();
  86. while (queue.length) {
  87. const child = queue.shift();
  88. if (!child) continue;
  89. arr.push(child);
  90. queue.push(...(vListRef.value?.children.get(child) ?? []).slice());
  91. }
  92. return arr;
  93. }
  94. function openAll(items) {
  95. let ids = [];
  96. for (const i of items) {
  97. if (!i.children) continue;
  98. ids.push(props.returnObject ? toRaw(i.raw) : i.value);
  99. if (i.children) {
  100. ids = ids.concat(openAll(i.children));
  101. }
  102. }
  103. return ids;
  104. }
  105. provide(VTreeviewSymbol, {
  106. visibleIds
  107. });
  108. provideDefaults({
  109. VTreeviewGroup: {
  110. activeColor,
  111. baseColor,
  112. color,
  113. collapseIcon: toRef(props, 'collapseIcon'),
  114. expandIcon: toRef(props, 'expandIcon')
  115. },
  116. VTreeviewItem: {
  117. activeClass: toRef(props, 'activeClass'),
  118. activeColor,
  119. baseColor,
  120. color,
  121. density: toRef(props, 'density'),
  122. disabled: toRef(props, 'disabled'),
  123. lines: toRef(props, 'lines'),
  124. variant: toRef(props, 'variant')
  125. }
  126. });
  127. useRender(() => {
  128. const listProps = VList.filterProps(props);
  129. const treeviewChildrenProps = VTreeviewChildren.filterProps(props);
  130. return _createVNode(VList, _mergeProps({
  131. "ref": vListRef
  132. }, listProps, {
  133. "class": ['v-treeview', props.class],
  134. "open-strategy": "multiple",
  135. "style": props.style,
  136. "opened": opened.value,
  137. "activated": activated.value,
  138. "onUpdate:activated": $event => activated.value = $event,
  139. "selected": selected.value,
  140. "onUpdate:selected": $event => selected.value = $event
  141. }), {
  142. default: () => [_createVNode(VTreeviewChildren, _mergeProps(treeviewChildrenProps, {
  143. "returnObject": props.returnObject,
  144. "items": items.value
  145. }), slots)]
  146. });
  147. });
  148. return {};
  149. }
  150. });
  151. //# sourceMappingURL=VTreeview.mjs.map