index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var vue = require('vue');
  4. var lodashUnified = require('lodash-unified');
  5. var menu = require('./menu.js');
  6. var store = require('./store.js');
  7. var node = require('./node.js');
  8. var config = require('./config.js');
  9. var utils = require('./utils.js');
  10. var types = require('./types.js');
  11. var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js');
  12. var arrays = require('../../../utils/arrays.js');
  13. var scroll = require('../../../utils/dom/scroll.js');
  14. var aria$1 = require('../../../utils/dom/aria.js');
  15. var event = require('../../../constants/event.js');
  16. var index = require('../../../hooks/use-namespace/index.js');
  17. var types$1 = require('../../../utils/types.js');
  18. var core = require('@vueuse/core');
  19. var aria = require('../../../constants/aria.js');
  20. const _sfc_main = vue.defineComponent({
  21. name: "ElCascaderPanel",
  22. components: {
  23. ElCascaderMenu: menu["default"]
  24. },
  25. props: {
  26. ...config.CommonProps,
  27. border: {
  28. type: Boolean,
  29. default: true
  30. },
  31. renderLabel: Function
  32. },
  33. emits: [event.UPDATE_MODEL_EVENT, event.CHANGE_EVENT, "close", "expand-change"],
  34. setup(props, { emit, slots }) {
  35. let manualChecked = false;
  36. const ns = index.useNamespace("cascader");
  37. const config$1 = config.useCascaderConfig(props);
  38. let store$1 = null;
  39. const initialLoaded = vue.ref(true);
  40. const menuList = vue.ref([]);
  41. const checkedValue = vue.ref(null);
  42. const menus = vue.ref([]);
  43. const expandingNode = vue.ref(null);
  44. const checkedNodes = vue.ref([]);
  45. const isHoverMenu = vue.computed(() => config$1.value.expandTrigger === "hover");
  46. const renderLabelFn = vue.computed(() => props.renderLabel || slots.default);
  47. const initStore = () => {
  48. const { options } = props;
  49. const cfg = config$1.value;
  50. manualChecked = false;
  51. store$1 = new store["default"](options, cfg);
  52. menus.value = [store$1.getNodes()];
  53. if (cfg.lazy && types$1.isEmpty(props.options)) {
  54. initialLoaded.value = false;
  55. lazyLoad(void 0, (list) => {
  56. if (list) {
  57. store$1 = new store["default"](list, cfg);
  58. menus.value = [store$1.getNodes()];
  59. }
  60. initialLoaded.value = true;
  61. syncCheckedValue(false, true);
  62. });
  63. } else {
  64. syncCheckedValue(false, true);
  65. }
  66. };
  67. const lazyLoad = (node$1, cb) => {
  68. const cfg = config$1.value;
  69. node$1 = node$1 || new node["default"]({}, cfg, void 0, true);
  70. node$1.loading = true;
  71. const resolve = (dataList) => {
  72. const _node = node$1;
  73. const parent = _node.root ? null : _node;
  74. dataList && (store$1 == null ? void 0 : store$1.appendNodes(dataList, parent));
  75. _node.loading = false;
  76. _node.loaded = true;
  77. _node.childrenData = _node.childrenData || [];
  78. cb && cb(dataList);
  79. };
  80. cfg.lazyLoad(node$1, resolve);
  81. };
  82. const expandNode = (node, silent) => {
  83. var _a;
  84. const { level } = node;
  85. const newMenus = menus.value.slice(0, level);
  86. let newExpandingNode;
  87. if (node.isLeaf) {
  88. newExpandingNode = node.pathNodes[level - 2];
  89. } else {
  90. newExpandingNode = node;
  91. newMenus.push(node.children);
  92. }
  93. if (((_a = expandingNode.value) == null ? void 0 : _a.uid) !== (newExpandingNode == null ? void 0 : newExpandingNode.uid)) {
  94. expandingNode.value = node;
  95. menus.value = newMenus;
  96. !silent && emit("expand-change", (node == null ? void 0 : node.pathValues) || []);
  97. }
  98. };
  99. const handleCheckChange = (node, checked, emitClose = true) => {
  100. const { checkStrictly, multiple } = config$1.value;
  101. const oldNode = checkedNodes.value[0];
  102. manualChecked = true;
  103. !multiple && (oldNode == null ? void 0 : oldNode.doCheck(false));
  104. node.doCheck(checked);
  105. calculateCheckedValue();
  106. emitClose && !multiple && !checkStrictly && emit("close");
  107. !emitClose && !multiple && !checkStrictly && expandParentNode(node);
  108. };
  109. const expandParentNode = (node) => {
  110. if (!node)
  111. return;
  112. node = node.parent;
  113. expandParentNode(node);
  114. node && expandNode(node);
  115. };
  116. const getFlattedNodes = (leafOnly) => {
  117. return store$1 == null ? void 0 : store$1.getFlattedNodes(leafOnly);
  118. };
  119. const getCheckedNodes = (leafOnly) => {
  120. var _a;
  121. return (_a = getFlattedNodes(leafOnly)) == null ? void 0 : _a.filter((node) => node.checked !== false);
  122. };
  123. const clearCheckedNodes = () => {
  124. checkedNodes.value.forEach((node) => node.doCheck(false));
  125. calculateCheckedValue();
  126. menus.value = menus.value.slice(0, 1);
  127. expandingNode.value = null;
  128. emit("expand-change", []);
  129. };
  130. const calculateCheckedValue = () => {
  131. var _a;
  132. const { checkStrictly, multiple } = config$1.value;
  133. const oldNodes = checkedNodes.value;
  134. const newNodes = getCheckedNodes(!checkStrictly);
  135. const nodes = utils.sortByOriginalOrder(oldNodes, newNodes);
  136. const values = nodes.map((node) => node.valueByOption);
  137. checkedNodes.value = nodes;
  138. checkedValue.value = multiple ? values : (_a = values[0]) != null ? _a : null;
  139. };
  140. const syncCheckedValue = (loaded = false, forced = false) => {
  141. const { modelValue } = props;
  142. const { lazy, multiple, checkStrictly } = config$1.value;
  143. const leafOnly = !checkStrictly;
  144. if (!initialLoaded.value || manualChecked || !forced && lodashUnified.isEqual(modelValue, checkedValue.value))
  145. return;
  146. if (lazy && !loaded) {
  147. const values = arrays.unique(lodashUnified.flattenDeep(arrays.castArray(modelValue)));
  148. const nodes = values.map((val) => store$1 == null ? void 0 : store$1.getNodeByValue(val)).filter((node) => !!node && !node.loaded && !node.loading);
  149. if (nodes.length) {
  150. nodes.forEach((node) => {
  151. lazyLoad(node, () => syncCheckedValue(false, forced));
  152. });
  153. } else {
  154. syncCheckedValue(true, forced);
  155. }
  156. } else {
  157. const values = multiple ? arrays.castArray(modelValue) : [modelValue];
  158. const nodes = arrays.unique(values.map((val) => store$1 == null ? void 0 : store$1.getNodeByValue(val, leafOnly)));
  159. syncMenuState(nodes, forced);
  160. checkedValue.value = lodashUnified.cloneDeep(modelValue);
  161. }
  162. };
  163. const syncMenuState = (newCheckedNodes, reserveExpandingState = true) => {
  164. const { checkStrictly } = config$1.value;
  165. const oldNodes = checkedNodes.value;
  166. const newNodes = newCheckedNodes.filter((node) => !!node && (checkStrictly || node.isLeaf));
  167. const oldExpandingNode = store$1 == null ? void 0 : store$1.getSameNode(expandingNode.value);
  168. const newExpandingNode = reserveExpandingState && oldExpandingNode || newNodes[0];
  169. if (newExpandingNode) {
  170. newExpandingNode.pathNodes.forEach((node) => expandNode(node, true));
  171. } else {
  172. expandingNode.value = null;
  173. }
  174. oldNodes.forEach((node) => node.doCheck(false));
  175. vue.reactive(newNodes).forEach((node) => node.doCheck(true));
  176. checkedNodes.value = newNodes;
  177. vue.nextTick(scrollToExpandingNode);
  178. };
  179. const scrollToExpandingNode = () => {
  180. if (!core.isClient)
  181. return;
  182. menuList.value.forEach((menu) => {
  183. const menuElement = menu == null ? void 0 : menu.$el;
  184. if (menuElement) {
  185. const container = menuElement.querySelector(`.${ns.namespace.value}-scrollbar__wrap`);
  186. const activeNode = menuElement.querySelector(`.${ns.b("node")}.${ns.is("active")}`) || menuElement.querySelector(`.${ns.b("node")}.in-active-path`);
  187. scroll.scrollIntoView(container, activeNode);
  188. }
  189. });
  190. };
  191. const handleKeyDown = (e) => {
  192. const target = e.target;
  193. const { code } = e;
  194. switch (code) {
  195. case aria.EVENT_CODE.up:
  196. case aria.EVENT_CODE.down: {
  197. e.preventDefault();
  198. const distance = code === aria.EVENT_CODE.up ? -1 : 1;
  199. aria$1.focusNode(aria$1.getSibling(target, distance, `.${ns.b("node")}[tabindex="-1"]`));
  200. break;
  201. }
  202. case aria.EVENT_CODE.left: {
  203. e.preventDefault();
  204. const preMenu = menuList.value[utils.getMenuIndex(target) - 1];
  205. const expandedNode = preMenu == null ? void 0 : preMenu.$el.querySelector(`.${ns.b("node")}[aria-expanded="true"]`);
  206. aria$1.focusNode(expandedNode);
  207. break;
  208. }
  209. case aria.EVENT_CODE.right: {
  210. e.preventDefault();
  211. const nextMenu = menuList.value[utils.getMenuIndex(target) + 1];
  212. const firstNode = nextMenu == null ? void 0 : nextMenu.$el.querySelector(`.${ns.b("node")}[tabindex="-1"]`);
  213. aria$1.focusNode(firstNode);
  214. break;
  215. }
  216. case aria.EVENT_CODE.enter:
  217. case aria.EVENT_CODE.numpadEnter:
  218. utils.checkNode(target);
  219. break;
  220. }
  221. };
  222. vue.provide(types.CASCADER_PANEL_INJECTION_KEY, vue.reactive({
  223. config: config$1,
  224. expandingNode,
  225. checkedNodes,
  226. isHoverMenu,
  227. initialLoaded,
  228. renderLabelFn,
  229. lazyLoad,
  230. expandNode,
  231. handleCheckChange
  232. }));
  233. vue.watch([config$1, () => props.options], initStore, {
  234. deep: true,
  235. immediate: true
  236. });
  237. vue.watch(() => props.modelValue, () => {
  238. manualChecked = false;
  239. syncCheckedValue();
  240. }, {
  241. deep: true
  242. });
  243. vue.watch(() => checkedValue.value, (val) => {
  244. if (!lodashUnified.isEqual(val, props.modelValue)) {
  245. emit(event.UPDATE_MODEL_EVENT, val);
  246. emit(event.CHANGE_EVENT, val);
  247. }
  248. });
  249. vue.onBeforeUpdate(() => menuList.value = []);
  250. vue.onMounted(() => !types$1.isEmpty(props.modelValue) && syncCheckedValue());
  251. return {
  252. ns,
  253. menuList,
  254. menus,
  255. checkedNodes,
  256. handleKeyDown,
  257. handleCheckChange,
  258. getFlattedNodes,
  259. getCheckedNodes,
  260. clearCheckedNodes,
  261. calculateCheckedValue,
  262. scrollToExpandingNode
  263. };
  264. }
  265. });
  266. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  267. const _component_el_cascader_menu = vue.resolveComponent("el-cascader-menu");
  268. return vue.openBlock(), vue.createElementBlock("div", {
  269. class: vue.normalizeClass([_ctx.ns.b("panel"), _ctx.ns.is("bordered", _ctx.border)]),
  270. onKeydown: _ctx.handleKeyDown
  271. }, [
  272. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.menus, (menu, index) => {
  273. return vue.openBlock(), vue.createBlock(_component_el_cascader_menu, {
  274. key: index,
  275. ref_for: true,
  276. ref: (item) => _ctx.menuList[index] = item,
  277. index,
  278. nodes: [...menu]
  279. }, {
  280. empty: vue.withCtx(() => [
  281. vue.renderSlot(_ctx.$slots, "empty")
  282. ]),
  283. _: 2
  284. }, 1032, ["index", "nodes"]);
  285. }), 128))
  286. ], 42, ["onKeydown"]);
  287. }
  288. var CascaderPanel = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["render", _sfc_render], ["__file", "index.vue"]]);
  289. exports["default"] = CascaderPanel;
  290. //# sourceMappingURL=index.js.map