提交 144ab577 编写于 作者: V vben

fix(modal): height calc error #161

上级 8d7d0835
......@@ -13,6 +13,7 @@
- 恢复 table 的`isTreeTable`属性
- 修复表格内存溢出问题
- 修复`layout` 收缩展开功能在分割模式下失效
- 修复 modal 高度计算错误
## 2.0.0-rc.15 (2020-12-31)
......
......@@ -256,8 +256,8 @@ yarn clean:lib # 删除node_modules,兼容window系统
如果这些插件对你有帮助,可以给一个 star 支持下
- [vite-plugin-mock](https://github.com/anncwb/vite-plugin-mock)
- [vite-plugin-html](https://github.com/anncwb/vite-plugin-html)
- [vite-plugin-mock](https://github.com/vbenjs/vite-plugin-mock)
- [vite-plugin-html](https://github.com/vbenjs/vite-plugin-html)
## 加入我们
......
......@@ -15,6 +15,7 @@
export default defineComponent({
name: 'BasicArrow',
inheritAttrs: false,
components: { RightOutlined },
props: {
// Expand contract, expand by default
......
......@@ -12,6 +12,7 @@
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({
name: 'BasicHelp',
inheritAttrs: false,
components: { Tooltip },
props: {
// max-width
......
......@@ -15,6 +15,7 @@
export default defineComponent({
name: 'BasicTitle',
inheritAttrs: false,
components: { BasicHelp },
props: {
helpMessage: {
......
......@@ -35,6 +35,7 @@
export default defineComponent({
name: 'LazyContainer',
inheritAttrs: false,
components: { Skeleton },
props: {
// Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time
......
......@@ -12,6 +12,7 @@
export default defineComponent({
name: 'ScrollContainer',
inheritAttrs: false,
components: { Scrollbar },
setup() {
const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
......
......@@ -8,19 +8,23 @@
import { propTypes } from '/@/utils/propTypes';
import { useLocale } from '/@/hooks/web/useLocale';
import { useModalContext } from '../../Modal';
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
export default defineComponent({
emits: ['change'],
inheritAttrs: false,
props: {
height: propTypes.number.def(360),
value: propTypes.string.def(''),
},
emits: ['change', 'get'],
setup(props, { attrs, emit }) {
const wrapRef = ref<ElRef>(null);
const vditorRef = ref<Nullable<Vditor>>(null);
const initedRef = ref(false);
const modalFn = useModalContext();
const lang = ref<Lang>();
const { getLang } = useLocale();
......@@ -66,10 +70,19 @@
initedRef.value = true;
}
const instance = {
getVditor: (): Vditor => vditorRef.value!,
};
onMounted(() => {
nextTick(() => {
init();
setTimeout(() => {
modalFn?.redoModalHeight?.();
}, 200);
});
emit('get', instance);
});
onUnmounted(() => {
......@@ -82,7 +95,7 @@
return {
wrapRef,
getVditor: (): Vditor => vditorRef.value!,
...instance,
};
},
});
......
......@@ -27,7 +27,7 @@
:height="getProps.height"
:visible="visibleRef"
:modalFooterHeight="footer !== undefined && !footer ? 0 : undefined"
v-bind="omit(getProps.wrapperProps, 'visible')"
v-bind="omit(getProps.wrapperProps, 'visible', 'height')"
@ext-height="handleExtHeight"
@height-change="handleHeightChange"
>
......@@ -51,6 +51,7 @@
watchEffect,
toRef,
getCurrentInstance,
nextTick,
} from 'vue';
import Modal from './components/Modal';
......@@ -67,6 +68,7 @@
import { omit } from 'lodash-es';
export default defineComponent({
name: 'BasicModal',
inheritAttrs: false,
components: { Modal, ModalWrapper, ModalClose, ModalFooter, ModalHeader },
props: basicProps,
emits: ['visible-change', 'height-change', 'cancel', 'ok', 'register'],
......
......@@ -31,6 +31,7 @@
export default defineComponent({
name: 'ModalWrapper',
inheritAttrs: false,
components: { Spin, ScrollContainer },
props: {
loading: propTypes.bool,
......@@ -51,6 +52,8 @@
const realHeightRef = ref(0);
const minRealHeightRef = ref(0);
let realHeight = 0;
let stopElResizeFn: Fn = () => {};
useWindowSizeFn(setModalHeight);
......@@ -137,8 +140,9 @@
if (!spinEl) return;
const realHeight = spinEl.scrollHeight;
if (!realHeight) {
realHeight = spinEl.scrollHeight;
}
if (props.fullScreen) {
realHeightRef.value =
window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight;
......@@ -147,7 +151,7 @@
? props.height
: realHeight > maxHeight
? maxHeight
: realHeight + 16 + 30;
: realHeight + 46;
}
emit('height-change', unref(realHeightRef));
} catch (error) {
......
......@@ -33,6 +33,7 @@
export default defineComponent({
name: 'Scrollbar',
inheritAttrs: false,
components: { Bar },
props: {
native: {
......@@ -91,12 +92,18 @@
onMounted(() => {
if (props.native) return;
nextTick(update);
!props.noresize && addResizeListener(resize.value, update);
if (!props.noresize) {
addResizeListener(resize.value, update);
addResizeListener(wrap.value, update);
}
});
onBeforeUnmount(() => {
if (props.native) return;
!props.noresize && removeResizeListener(resize.value, update);
if (!props.noresize) {
removeResizeListener(resize.value, update);
removeResizeListener(wrap.value, update);
}
});
const style = computed(() => {
let style: any = props.wrapStyle;
......@@ -127,7 +134,7 @@
&__wrap {
height: 100%;
overflow: scroll;
overflow: auto;
&--hidden-default {
scrollbar-width: none;
......
......@@ -31,6 +31,7 @@
export default defineComponent({
name: 'Tinymce',
inheritAttrs: false,
props: basicProps,
emits: ['change', 'update:modelValue'],
setup(props, { emit, attrs }) {
......
......@@ -15,6 +15,7 @@ import { extendSlots } from '/@/utils/helper/tsxHelper';
import { basicProps } from './props';
import { useTree } from './useTree';
import { useExpose } from '/@/hooks/core/useExpose';
import { onMounted } from 'vue';
interface State {
expandedKeys: Keys;
......@@ -25,7 +26,7 @@ const prefixCls = 'basic-tree';
export default defineComponent({
name: 'BasicTree',
props: basicProps,
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value'],
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
setup(props, { attrs, slots, emit }) {
const state = reactive<State>({
expandedKeys: props.expandedKeys || [],
......@@ -182,7 +183,7 @@ export default defineComponent({
state.checkedKeys = props.checkedKeys;
});
useExpose<TreeActionType>({
const instance: TreeActionType = {
setExpandedKeys,
getExpandedKeys,
setSelectedKeys,
......@@ -195,6 +196,12 @@ export default defineComponent({
filterByLevel: (level: number) => {
state.expandedKeys = filterByLevel(level);
},
};
useExpose<TreeActionType>(instance);
onMounted(() => {
emit('get', instance);
});
return () => {
......
import type { InjectionKey, ComputedRef, Ref } from 'vue';
import { createContext, useContext } from '/@/hooks/core/useContext';
import {} from 'vue';
export interface PageContextProps {
contentHeight: ComputedRef<number>;
pageHeight: Ref<number>;
......
......@@ -113,7 +113,6 @@
const activePath = ref('');
const chilrenMenus = ref<Menu[]>([]);
const openMenu = ref(false);
const isInit = ref(false);
const dragBarRef = ref<ElRef>(null);
const sideRef = ref<ElRef>(null);
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
......@@ -251,8 +250,8 @@
}
function handleClickOutside() {
setActive(true);
closeMenu();
setActive();
}
function getItemEvents(item: Menu) {
......
......@@ -75,7 +75,7 @@ export function isOperaFn() {
* set page Title
* @param {*} title :page Title
*/
const setDocumentTitle = (title: string) => {
function setDocumentTitle(title: string) {
document.title = title;
const ua = navigator.userAgent;
const regex = /\bMicroMessenger\/([\d.]+)/;
......@@ -91,7 +91,7 @@ const setDocumentTitle = (title: string) => {
};
document.body.appendChild(i);
}
};
}
export function setTitle(title: string, appTitle?: string) {
if (title) {
......
......@@ -5,10 +5,10 @@
* @param String color 十六进制颜色值
* @return Boolean
*/
export const isHexColor = function (color: string) {
export function isHexColor(color: string) {
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
return reg.test(color);
};
}
/**
* RGB 颜色值转换为 十六进制颜色值.
......@@ -19,18 +19,18 @@ export const isHexColor = function (color: string) {
* @param g
* @param b
*/
export const rgbToHex = function (r: number, g: number, b: number) {
export function rgbToHex(r: number, g: number, b: number) {
// tslint:disable-next-line:no-bitwise
const hex = ((r << 16) | (g << 8) | b).toString(16);
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex;
};
}
/**
* Transform a HEX color to its RGB representation
* @param {string} hex The color to transform
* @returns The RGB representation of the passed color
*/
export const hexToRGB = function (hex: string) {
export function hexToRGB(hex: string) {
let sHex = hex.toLowerCase();
if (isHexColor(hex)) {
if (sHex.length === 4) {
......@@ -47,16 +47,16 @@ export const hexToRGB = function (hex: string) {
return 'RGB(' + sColorChange.join(',') + ')';
}
return sHex;
};
}
export const colorIsDark = (color: string) => {
export function colorIsDark(color: string) {
if (!isHexColor(color)) return;
const [r, g, b] = hexToRGB(color)
.replace(/(?:\(|\)|rgb|RGB)*/g, '')
.split(',')
.map((item) => Number(item));
return r * 0.299 + g * 0.578 + b * 0.114 < 192;
};
}
/**
* Darkens a HEX color given the passed percentage
......@@ -64,14 +64,14 @@ export const colorIsDark = (color: string) => {
* @param {number} amount The amount to change the color by
* @returns {string} The HEX representation of the processed color
*/
export const darken = (color: string, amount: number) => {
export function darken(color: string, amount: number) {
color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color;
amount = Math.trunc((255 * amount) / 100);
return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight(
color.substring(2, 4),
amount
)}${subtractLight(color.substring(4, 6), amount)}`;
};
}
/**
* Lightens a 6 char HEX color according to the passed percentage
......@@ -79,14 +79,14 @@ export const darken = (color: string, amount: number) => {
* @param {number} amount The amount to change the color by
* @returns {string} The processed color represented as HEX
*/
export const lighten = (color: string, amount: number) => {
export function lighten(color: string, amount: number) {
color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color;
amount = Math.trunc((255 * amount) / 100);
return `#${addLight(color.substring(0, 2), amount)}${addLight(
color.substring(2, 4),
amount
)}${addLight(color.substring(4, 6), amount)}`;
};
}
/* Suma el porcentaje indicado a un color (RR, GG o BB) hexadecimal para aclararlo */
/**
......@@ -95,11 +95,11 @@ export const lighten = (color: string, amount: number) => {
* @param {number} amount The amount to change the color by
* @returns {string} The processed part of the color
*/
const addLight = (color: string, amount: number) => {
function addLight(color: string, amount: number) {
const cc = parseInt(color, 16) + amount;
const c = cc > 255 ? 255 : cc;
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
};
}
/**
* Calculates luminance of an rgb color
......@@ -107,33 +107,36 @@ const addLight = (color: string, amount: number) => {
* @param {number} g green
* @param {number} b blue
*/
const luminanace = (r: number, g: number, b: number) => {
function luminanace(r: number, g: number, b: number) {
const a = [r, g, b].map((v) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};
}
/**
* Calculates contrast between two rgb colors
* @param {string} rgb1 rgb color 1
* @param {string} rgb2 rgb color 2
*/
const contrast = (rgb1: string[], rgb2: number[]) =>
(luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
(luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05);
function contrast(rgb1: string[], rgb2: number[]) {
return (
(luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) /
(luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05)
);
}
/**
* Determines what the best text color is (black or white) based con the contrast with the background
* @param hexColor - Last selected color by the user
*/
export const calculateBestTextColor = (hexColor: string) => {
export function calculateBestTextColor(hexColor: string) {
const rgbColor = hexToRGB(hexColor.substring(1));
const contrastWithBlack = contrast(rgbColor.split(','), [0, 0, 0]);
return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF';
};
}
/**
* Subtracts the indicated percentage to the R, G or B of a HEX color
......@@ -141,8 +144,8 @@ export const calculateBestTextColor = (hexColor: string) => {
* @param {number} amount The amount to change the color by
* @returns {string} The processed part of the color
*/
const subtractLight = (color: string, amount: number) => {
function subtractLight(color: string, amount: number) {
const cc = parseInt(color, 16) - amount;
const c = cc < 0 ? 0 : cc;
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
};
}
......@@ -14,7 +14,7 @@ export function formatToDate(date: moment.MomentInput = null, format = DATE_FORM
return moment(date).format(format);
}
export const formatAgo = (str: string | number) => {
export function formatAgo(str: string | number) {
if (!str) return '';
const date = new Date(Number(str));
const time = new Date().getTime() - date.getTime(); // 现在的时间-传入的时间 = 相差的时间(单位 = 毫秒)
......@@ -35,6 +35,6 @@ export const formatAgo = (str: string | number) => {
} else {
return parseInt(String(time / 31536000000)) + '年前';
}
};
}
export const dateUtil = moment;
......@@ -132,7 +132,7 @@ export function hackCss(attr: string, value: string) {
}
/* istanbul ignore next */
export const on = function (
export function on(
element: Element | HTMLElement | Document | Window,
event: string,
handler: EventListenerOrEventListenerObject
......@@ -140,10 +140,10 @@ export const on = function (
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
};
}
/* istanbul ignore next */
export const off = function (
export function off(
element: Element | HTMLElement | Document | Window,
event: string,
handler: Fn
......@@ -151,10 +151,10 @@ export const off = function (
if (element && event && handler) {
element.removeEventListener(event, handler, false);
}
};
}
/* istanbul ignore next */
export const once = function (el: HTMLElement, event: string, fn: EventListener): void {
export function once(el: HTMLElement, event: string, fn: EventListener): void {
const listener = function (this: any, ...args: unknown[]) {
if (fn) {
fn.apply(this, args);
......@@ -162,4 +162,4 @@ export const once = function (el: HTMLElement, event: string, fn: EventListener)
off(el, event, listener);
};
on(el, event, listener);
};
}
import type { GlobEnvConfig } from '/@/types/config';
export const getGlobEnvConfig = (): GlobEnvConfig => {
export function getGlobEnvConfig(): GlobEnvConfig {
const env = import.meta.env;
return (env as unknown) as GlobEnvConfig;
};
}
/**
* @description: 开发模式
......@@ -20,25 +20,33 @@ export const prodMode = 'production';
* @returns:
* @example:
*/
export const getEnv = (): string => import.meta.env.MODE;
export function getEnv(): string {
return import.meta.env.MODE;
}
/**
* @description: 是否是开发模式
* @returns:
* @example:
*/
export const isDevMode = (): boolean => import.meta.env.DEV;
export function isDevMode(): boolean {
return import.meta.env.DEV;
}
/**
* @description: 是否是生产模式模式
* @returns:
* @example:
*/
export const isProdMode = (): boolean => import.meta.env.PROD;
export function isProdMode(): boolean {
return import.meta.env.PROD;
}
/**
* @description: 是否开启mock
* @returns:
* @example:
*/
export const isUseMock = (): boolean => import.meta.env.VITE_USE_MOCK === 'true';
export function isUseMock(): boolean {
return import.meta.env.VITE_USE_MOCK === 'true';
}
......@@ -3,7 +3,7 @@ import ResizeObserver from 'resize-observer-polyfill';
const isServer = typeof window === 'undefined';
/* istanbul ignore next */
const resizeHandler = function (entries: any[]) {
function resizeHandler(entries: any[]) {
for (const entry of entries) {
const listeners = entry.target.__resizeListeners__ || [];
if (listeners.length) {
......@@ -12,10 +12,10 @@ const resizeHandler = function (entries: any[]) {
});
}
}
};
}
/* istanbul ignore next */
export const addResizeListener = function (element: any, fn: () => any) {
export function addResizeListener(element: any, fn: () => any) {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
......@@ -23,13 +23,13 @@ export const addResizeListener = function (element: any, fn: () => any) {
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};
}
/* istanbul ignore next */
export const removeResizeListener = function (element: any, fn: () => any) {
export function removeResizeListener(element: any, fn: () => any) {
if (!element || !element.__resizeListeners__) return;
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
element.__ro__.disconnect();
}
};
}
......@@ -4,6 +4,6 @@
export function triggerWindowResize() {
const event = document.createEvent('HTMLEvents');
event.initEvent('resize', true, true);
(event as ChangeEvent).eventType = 'message';
(event as any).eventType = 'message';
window.dispatchEvent(event);
}
......@@ -4,6 +4,6 @@ import pkg from '../../../package.json';
const globSetting = useGlobSetting();
// Generate cache key according to version
export const getStorageShortName = () => {
export function getStorageShortName() {
return `${globSetting.shortName}__${getEnv()}${`__${pkg.version}`}__`.toUpperCase();
};
}
......@@ -85,3 +85,17 @@ export function getDynamicProps<T, U>(props: T): Partial<U> {
return ret as Partial<U>;
}
export function getLastItem<T extends any>(list: T) {
if (Array.isArray(list)) {
return list.slice(-1)[0];
}
if (list instanceof Set) {
return Array.from(list).slice(-1)[0];
}
if (list instanceof Map) {
return Array.from(list.values()).slice(-1)[0];
}
}
......@@ -4,17 +4,33 @@ export function is(val: unknown, type: string) {
return toString.call(val) === `[object ${type}]`;
}
export const isDef = <T = unknown>(val?: T): val is T => {
export function isDef<T = unknown>(val?: T): val is T {
return typeof val !== 'undefined';
};
}
export const isUnDef = <T = unknown>(val?: T): val is T => {
export function isUnDef<T = unknown>(val?: T): val is T {
return !isDef(val);
};
}
export const isObject = (val: any): val is Record<any, any> => {
export function isObject(val: any): val is Record<any, any> {
return val !== null && is(val, 'Object');
};
}
export function isEmpty<T = unknown>(val: T): val is T {
if (isArray(val) || isString(val)) {
return val.length === 0;
}
if (val instanceof Map || val instanceof Set) {
return val.size === 0;
}
if (isObject(val)) {
return Object.keys(val).length === 0;
}
return false;
}
export function isDate(val: unknown): val is Date {
return is(val, 'Date');
......@@ -40,7 +56,9 @@ export function isString(val: unknown): val is string {
return is(val, 'String');
}
export const isFunction = (val: unknown): val is Function => typeof val === 'function';
export function isFunction(val: unknown): val is Function {
return typeof val === 'function';
}
export function isBoolean(val: unknown): val is boolean {
return is(val, 'Boolean');
......@@ -54,13 +72,13 @@ export function isArray(val: any): val is Array<any> {
return val && Array.isArray(val);
}
export const isWindow = (val: any): val is Window => {
export function isWindow(val: any): val is Window {
return typeof window !== 'undefined' && is(val, 'Window');
};
}
export const isElement = (val: unknown): val is Element => {
export function isElement(val: unknown): val is Element {
return isObject(val) && !!val.tagName;
};
}
export const isServer = typeof window === 'undefined';
......@@ -70,17 +88,17 @@ export function isImageDom(o: Element) {
return o && ['IMAGE', 'IMG'].includes(o.tagName);
}
export const isTextarea = (element: Element | null): element is HTMLTextAreaElement => {
export function isTextarea(element: Element | null): element is HTMLTextAreaElement {
return element !== null && element.tagName.toLowerCase() === 'textarea';
};
}
export const isMobile = (): boolean => {
export function isMobile(): boolean {
return !!navigator.userAgent.match(
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
);
};
}
export const isUrl = (path: string): boolean => {
export function isUrl(path: string): boolean {
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
return reg.test(path);
};
}
import { isWindow } from '/@/utils/is';
let scrollBarWidth: number;
export default function (): number {
if (!isWindow) return 0;
if (scrollBarWidth !== undefined) return scrollBarWidth;
const outer = document.createElement('div');
outer.className = 'scrollbar__wrap';
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.position = 'absolute';
outer.style.top = '-9999px';
document.body.appendChild(outer);
const widthNoScroll = outer.offsetWidth;
outer.style.overflow = 'scroll';
const inner = document.createElement('div');
inner.style.width = '100%';
outer.appendChild(inner);
const widthWithScroll = inner.offsetWidth;
const parentNode = outer.parentNode;
parentNode && parentNode.removeChild(outer);
scrollBarWidth = widthNoScroll - widthWithScroll;
return scrollBarWidth;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册