index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import { resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
  4. var __rest = this && this.__rest || function (s, e) {
  5. var t = {};
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  7. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  8. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { inject, nextTick, defineComponent, shallowRef, onMounted, provide, onUnmounted, watch, computed } from 'vue';
  13. import { getPropsSlot, initDefaultProps } from '../_util/props-util';
  14. import classnames from '../_util/classNames';
  15. import VcDrawer from '../vc-drawer';
  16. import PropTypes from '../_util/vue-types';
  17. import CloseOutlined from "@ant-design/icons-vue/es/icons/CloseOutlined";
  18. import useConfigInject from '../config-provider/hooks/useConfigInject';
  19. import { objectType, withInstall } from '../_util/type';
  20. import omit from '../_util/omit';
  21. import devWarning from '../vc-util/devWarning';
  22. import useStyle from './style';
  23. import { NoCompactStyle } from '../space/Compact';
  24. import isNumeric from '../_util/isNumeric';
  25. import { getTransitionName, getTransitionProps } from '../_util/transition';
  26. const PlacementTypes = ['top', 'right', 'bottom', 'left'];
  27. const SizeTypes = ['default', 'large'];
  28. const defaultPushState = {
  29. distance: 180
  30. };
  31. export const drawerProps = () => ({
  32. autofocus: {
  33. type: Boolean,
  34. default: undefined
  35. },
  36. closable: {
  37. type: Boolean,
  38. default: undefined
  39. },
  40. closeIcon: PropTypes.any,
  41. destroyOnClose: {
  42. type: Boolean,
  43. default: undefined
  44. },
  45. forceRender: {
  46. type: Boolean,
  47. default: undefined
  48. },
  49. getContainer: {
  50. type: [String, Function, Boolean, Object],
  51. default: undefined
  52. },
  53. maskClosable: {
  54. type: Boolean,
  55. default: undefined
  56. },
  57. mask: {
  58. type: Boolean,
  59. default: undefined
  60. },
  61. maskStyle: objectType(),
  62. rootClassName: String,
  63. rootStyle: objectType(),
  64. size: {
  65. type: String
  66. },
  67. drawerStyle: objectType(),
  68. headerStyle: objectType(),
  69. bodyStyle: objectType(),
  70. contentWrapperStyle: {
  71. type: Object,
  72. default: undefined
  73. },
  74. title: PropTypes.any,
  75. /** @deprecated Please use `open` instead */
  76. visible: {
  77. type: Boolean,
  78. default: undefined
  79. },
  80. open: {
  81. type: Boolean,
  82. default: undefined
  83. },
  84. width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  85. height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  86. zIndex: Number,
  87. prefixCls: String,
  88. push: PropTypes.oneOfType([PropTypes.looseBool, {
  89. type: Object
  90. }]),
  91. placement: PropTypes.oneOf(PlacementTypes),
  92. keyboard: {
  93. type: Boolean,
  94. default: undefined
  95. },
  96. extra: PropTypes.any,
  97. footer: PropTypes.any,
  98. footerStyle: objectType(),
  99. level: PropTypes.any,
  100. levelMove: {
  101. type: [Number, Array, Function]
  102. },
  103. handle: PropTypes.any,
  104. /** @deprecated Use `@afterVisibleChange` instead */
  105. afterVisibleChange: Function,
  106. /** @deprecated Please use `@afterOpenChange` instead */
  107. onAfterVisibleChange: Function,
  108. onAfterOpenChange: Function,
  109. /** @deprecated Please use `onUpdate:open` instead */
  110. 'onUpdate:visible': Function,
  111. 'onUpdate:open': Function,
  112. onClose: Function
  113. });
  114. const Drawer = defineComponent({
  115. compatConfig: {
  116. MODE: 3
  117. },
  118. name: 'ADrawer',
  119. inheritAttrs: false,
  120. props: initDefaultProps(drawerProps(), {
  121. closable: true,
  122. placement: 'right',
  123. maskClosable: true,
  124. mask: true,
  125. level: null,
  126. keyboard: true,
  127. push: defaultPushState
  128. }),
  129. slots: Object,
  130. // emits: ['update:visible', 'close', 'afterVisibleChange'],
  131. setup(props, _ref) {
  132. let {
  133. emit,
  134. slots,
  135. attrs
  136. } = _ref;
  137. const sPush = shallowRef(false);
  138. const destroyClose = shallowRef(false);
  139. const vcDrawer = shallowRef(null);
  140. const load = shallowRef(false);
  141. const visible = shallowRef(false);
  142. const mergedOpen = computed(() => {
  143. var _a;
  144. return (_a = props.open) !== null && _a !== void 0 ? _a : props.visible;
  145. });
  146. watch(mergedOpen, () => {
  147. if (mergedOpen.value) {
  148. load.value = true;
  149. } else {
  150. visible.value = false;
  151. }
  152. }, {
  153. immediate: true
  154. });
  155. watch([mergedOpen, load], () => {
  156. if (mergedOpen.value && load.value) {
  157. visible.value = true;
  158. }
  159. }, {
  160. immediate: true
  161. });
  162. const parentDrawerOpts = inject('parentDrawerOpts', null);
  163. const {
  164. prefixCls,
  165. getPopupContainer,
  166. direction
  167. } = useConfigInject('drawer', props);
  168. const [wrapSSR, hashId] = useStyle(prefixCls);
  169. const getContainer = computed(() =>
  170. // 有可能为 false,所以不能直接判断
  171. props.getContainer === undefined && (getPopupContainer === null || getPopupContainer === void 0 ? void 0 : getPopupContainer.value) ? () => getPopupContainer.value(document.body) : props.getContainer);
  172. devWarning(!props.afterVisibleChange, 'Drawer', '`afterVisibleChange` prop is deprecated, please use `@afterVisibleChange` event instead');
  173. // ========================== Warning ===========================
  174. if (process.env.NODE_ENV !== 'production') {
  175. [['visible', 'open'], ['onUpdate:visible', 'onUpdate:open'], ['onAfterVisibleChange', 'onAfterOpenChange']].forEach(_ref2 => {
  176. let [deprecatedName, newName] = _ref2;
  177. devWarning(!props[deprecatedName], 'Drawer', `\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`);
  178. });
  179. }
  180. const setPush = () => {
  181. sPush.value = true;
  182. };
  183. const setPull = () => {
  184. sPush.value = false;
  185. nextTick(() => {
  186. domFocus();
  187. });
  188. };
  189. provide('parentDrawerOpts', {
  190. setPush,
  191. setPull
  192. });
  193. onMounted(() => {
  194. if (mergedOpen.value && parentDrawerOpts) {
  195. parentDrawerOpts.setPush();
  196. }
  197. });
  198. onUnmounted(() => {
  199. if (parentDrawerOpts) {
  200. parentDrawerOpts.setPull();
  201. }
  202. });
  203. watch(visible, () => {
  204. if (parentDrawerOpts) {
  205. if (visible.value) {
  206. parentDrawerOpts.setPush();
  207. } else {
  208. parentDrawerOpts.setPull();
  209. }
  210. }
  211. }, {
  212. flush: 'post'
  213. });
  214. const domFocus = () => {
  215. var _a, _b;
  216. (_b = (_a = vcDrawer.value) === null || _a === void 0 ? void 0 : _a.domFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
  217. };
  218. const close = e => {
  219. emit('update:visible', false);
  220. emit('update:open', false);
  221. emit('close', e);
  222. };
  223. const afterVisibleChange = open => {
  224. var _a;
  225. if (!open) {
  226. if (destroyClose.value === false) {
  227. // set true only once
  228. destroyClose.value = true;
  229. }
  230. if (props.destroyOnClose) {
  231. load.value = false;
  232. }
  233. }
  234. (_a = props.afterVisibleChange) === null || _a === void 0 ? void 0 : _a.call(props, open);
  235. emit('afterVisibleChange', open);
  236. emit('afterOpenChange', open);
  237. };
  238. const pushTransform = computed(() => {
  239. const {
  240. push,
  241. placement
  242. } = props;
  243. let distance;
  244. if (typeof push === 'boolean') {
  245. distance = push ? defaultPushState.distance : 0;
  246. } else {
  247. distance = push.distance;
  248. }
  249. distance = parseFloat(String(distance || 0));
  250. if (placement === 'left' || placement === 'right') {
  251. return `translateX(${placement === 'left' ? distance : -distance}px)`;
  252. }
  253. if (placement === 'top' || placement === 'bottom') {
  254. return `translateY(${placement === 'top' ? distance : -distance}px)`;
  255. }
  256. return null;
  257. });
  258. // ============================ Size ============================
  259. const mergedWidth = computed(() => {
  260. var _a;
  261. return (_a = props.width) !== null && _a !== void 0 ? _a : props.size === 'large' ? 736 : 378;
  262. });
  263. const mergedHeight = computed(() => {
  264. var _a;
  265. return (_a = props.height) !== null && _a !== void 0 ? _a : props.size === 'large' ? 736 : 378;
  266. });
  267. const offsetStyle = computed(() => {
  268. // https://github.com/ant-design/ant-design/issues/24287
  269. const {
  270. mask,
  271. placement
  272. } = props;
  273. if (!visible.value && !mask) {
  274. return {};
  275. }
  276. const val = {};
  277. if (placement === 'left' || placement === 'right') {
  278. val.width = isNumeric(mergedWidth.value) ? `${mergedWidth.value}px` : mergedWidth.value;
  279. } else {
  280. val.height = isNumeric(mergedHeight.value) ? `${mergedHeight.value}px` : mergedHeight.value;
  281. }
  282. return val;
  283. });
  284. const wrapperStyle = computed(() => {
  285. const {
  286. zIndex,
  287. contentWrapperStyle
  288. } = props;
  289. const val = offsetStyle.value;
  290. return [{
  291. zIndex,
  292. transform: sPush.value ? pushTransform.value : undefined
  293. }, _extends({}, contentWrapperStyle), val];
  294. });
  295. const renderHeader = prefixCls => {
  296. const {
  297. closable,
  298. headerStyle
  299. } = props;
  300. const extra = getPropsSlot(slots, props, 'extra');
  301. const title = getPropsSlot(slots, props, 'title');
  302. if (!title && !closable) {
  303. return null;
  304. }
  305. return _createVNode("div", {
  306. "class": classnames(`${prefixCls}-header`, {
  307. [`${prefixCls}-header-close-only`]: closable && !title && !extra
  308. }),
  309. "style": headerStyle
  310. }, [_createVNode("div", {
  311. "class": `${prefixCls}-header-title`
  312. }, [renderCloseIcon(prefixCls), title && _createVNode("div", {
  313. "class": `${prefixCls}-title`
  314. }, [title])]), extra && _createVNode("div", {
  315. "class": `${prefixCls}-extra`
  316. }, [extra])]);
  317. };
  318. const renderCloseIcon = prefixCls => {
  319. var _a;
  320. const {
  321. closable
  322. } = props;
  323. const $closeIcon = slots.closeIcon ? (_a = slots.closeIcon) === null || _a === void 0 ? void 0 : _a.call(slots) : props.closeIcon;
  324. return closable && _createVNode("button", {
  325. "key": "closer",
  326. "onClick": close,
  327. "aria-label": "Close",
  328. "class": `${prefixCls}-close`
  329. }, [$closeIcon === undefined ? _createVNode(CloseOutlined, null, null) : $closeIcon]);
  330. };
  331. const renderBody = prefixCls => {
  332. var _a;
  333. if (destroyClose.value && !props.forceRender && !load.value) {
  334. return null;
  335. }
  336. const {
  337. bodyStyle,
  338. drawerStyle
  339. } = props;
  340. return _createVNode("div", {
  341. "class": `${prefixCls}-wrapper-body`,
  342. "style": drawerStyle
  343. }, [renderHeader(prefixCls), _createVNode("div", {
  344. "key": "body",
  345. "class": `${prefixCls}-body`,
  346. "style": bodyStyle
  347. }, [(_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)]), renderFooter(prefixCls)]);
  348. };
  349. const renderFooter = prefixCls => {
  350. const footer = getPropsSlot(slots, props, 'footer');
  351. if (!footer) {
  352. return null;
  353. }
  354. const footerClassName = `${prefixCls}-footer`;
  355. return _createVNode("div", {
  356. "class": footerClassName,
  357. "style": props.footerStyle
  358. }, [footer]);
  359. };
  360. const drawerClassName = computed(() => classnames({
  361. 'no-mask': !props.mask,
  362. [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
  363. }, props.rootClassName, hashId.value));
  364. // =========================== Motion ===========================
  365. const maskMotion = computed(() => {
  366. return getTransitionProps(getTransitionName(prefixCls.value, 'mask-motion'));
  367. });
  368. const panelMotion = motionPlacement => {
  369. return getTransitionProps(getTransitionName(prefixCls.value, `panel-motion-${motionPlacement}`));
  370. };
  371. return () => {
  372. const {
  373. width,
  374. height,
  375. placement,
  376. mask,
  377. forceRender
  378. } = props,
  379. rest = __rest(props, ["width", "height", "placement", "mask", "forceRender"]);
  380. const vcDrawerProps = _extends(_extends(_extends({}, attrs), omit(rest, ['size', 'closeIcon', 'closable', 'destroyOnClose', 'drawerStyle', 'headerStyle', 'bodyStyle', 'title', 'push', 'onAfterVisibleChange', 'onClose', 'onUpdate:visible', 'onUpdate:open', 'visible'])), {
  381. forceRender,
  382. onClose: close,
  383. afterVisibleChange,
  384. handler: false,
  385. prefixCls: prefixCls.value,
  386. open: visible.value,
  387. showMask: mask,
  388. placement,
  389. ref: vcDrawer
  390. });
  391. return wrapSSR(_createVNode(NoCompactStyle, null, {
  392. default: () => [_createVNode(VcDrawer, _objectSpread(_objectSpread({}, vcDrawerProps), {}, {
  393. "maskMotion": maskMotion.value,
  394. "motion": panelMotion,
  395. "width": mergedWidth.value,
  396. "height": mergedHeight.value,
  397. "getContainer": getContainer.value,
  398. "rootClassName": drawerClassName.value,
  399. "rootStyle": props.rootStyle,
  400. "contentWrapperStyle": wrapperStyle.value
  401. }), {
  402. handler: props.handle ? () => props.handle : slots.handle,
  403. default: () => renderBody(prefixCls.value)
  404. })]
  405. }));
  406. };
  407. }
  408. });
  409. export default withInstall(Drawer);