perf: improve overall theme color matching

This commit is contained in:
vince
2024-07-15 23:53:58 +08:00
parent caf1fc4375
commit f95d9aa609
39 changed files with 525 additions and 843 deletions

View File

@@ -0,0 +1,9 @@
export * from './use-content-height';
export * from './use-namespace';
export * from './use-sortable';
export {
useEmitAsProps,
useForwardExpose,
useForwardProps,
useForwardPropsEmits,
} from 'radix-vue';

View File

@@ -0,0 +1,45 @@
import { computed, onMounted, ref, watch } from 'vue';
import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/constants';
import { getElementVisibleHeight } from '@vben-core/toolkit';
import { useCssVar, useDebounceFn, useWindowSize } from '@vueuse/core';
/**
* @zh_CN 获取内容高度(可视区域,不包含滚动条)
*/
function useContentHeight() {
const contentHeight = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT);
const contentStyles = computed(() => {
return {
height: `var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT})`,
};
});
return { contentHeight, contentStyles };
}
/**
* @zh_CN 创建内容高度监听
*/
function useContentHeightListener() {
const contentElement = ref<HTMLDivElement | null>(null);
const { height, width } = useWindowSize();
const contentHeight = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT);
const debouncedCalcHeight = useDebounceFn(() => {
contentHeight.value = `${getElementVisibleHeight(contentElement.value)}px`;
}, 200);
watch([height, width], () => {
debouncedCalcHeight();
});
onMounted(() => {
debouncedCalcHeight();
});
return { contentElement };
}
export { useContentHeight, useContentHeightListener };

View File

@@ -0,0 +1,105 @@
/**
* @see copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-namespace/index.ts
*/
export const defaultNamespace = 'vben';
const statePrefix = 'is-';
const _bem = (
namespace: string,
block: string,
blockSuffix: string,
element: string,
modifier: string,
) => {
let cls = `${namespace}-${block}`;
if (blockSuffix) {
cls += `-${blockSuffix}`;
}
if (element) {
cls += `__${element}`;
}
if (modifier) {
cls += `--${modifier}`;
}
return cls;
};
const is: {
(name: string): string;
// eslint-disable-next-line @typescript-eslint/unified-signatures
(name: string, state: boolean | undefined): string;
} = (name: string, ...args: [] | [boolean | undefined]) => {
const state = args.length > 0 ? args[0] : true;
return name && state ? `${statePrefix}${name}` : '';
};
const useNamespace = (block: string) => {
const namespace = defaultNamespace;
const b = (blockSuffix = '') => _bem(namespace, block, blockSuffix, '', '');
const e = (element?: string) =>
element ? _bem(namespace, block, '', element, '') : '';
const m = (modifier?: string) =>
modifier ? _bem(namespace, block, '', '', modifier) : '';
const be = (blockSuffix?: string, element?: string) =>
blockSuffix && element
? _bem(namespace, block, blockSuffix, element, '')
: '';
const em = (element?: string, modifier?: string) =>
element && modifier ? _bem(namespace, block, '', element, modifier) : '';
const bm = (blockSuffix?: string, modifier?: string) =>
blockSuffix && modifier
? _bem(namespace, block, blockSuffix, '', modifier)
: '';
const bem = (blockSuffix?: string, element?: string, modifier?: string) =>
blockSuffix && element && modifier
? _bem(namespace, block, blockSuffix, element, modifier)
: '';
// for css var
// --el-xxx: value;
const cssVar = (object: Record<string, string>) => {
const styles: Record<string, string> = {};
for (const key in object) {
if (object[key]) {
styles[`--${namespace}-${key}`] = object[key];
}
}
return styles;
};
// with block
const cssVarBlock = (object: Record<string, string>) => {
const styles: Record<string, string> = {};
for (const key in object) {
if (object[key]) {
styles[`--${namespace}-${block}-${key}`] = object[key];
}
}
return styles;
};
const cssVarName = (name: string) => `--${namespace}-${name}`;
const cssVarBlockName = (name: string) => `--${namespace}-${block}-${name}`;
return {
b,
be,
bem,
bm,
// css
cssVar,
cssVarBlock,
cssVarBlockName,
cssVarName,
e,
em,
is,
m,
namespace,
};
};
type UseNamespaceReturn = ReturnType<typeof useNamespace>;
export type { UseNamespaceReturn };
export { useNamespace };

View File

@@ -0,0 +1,49 @@
import type { SortableOptions } from 'sortablejs';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useSortable } from './use-sortable';
describe('useSortable', () => {
beforeEach(() => {
vi.mock('sortablejs/modular/sortable.complete.esm.js', () => ({
default: {
create: vi.fn(),
},
}));
});
it('should call Sortable.create with the correct options', async () => {
// Create a mock element
const mockElement = document.createElement('div') as HTMLDivElement;
// Define custom options
const customOptions: SortableOptions = {
group: 'test-group',
sort: false,
};
// Use the useSortable function
const { initializeSortable } = useSortable(mockElement, customOptions);
// Initialize sortable
await initializeSortable();
// Import sortablejs to access the mocked create function
const Sortable = await import(
// @ts-expect-error - This is a dynamic import
'sortablejs/modular/sortable.complete.esm.js'
);
// Verify that Sortable.create was called with the correct parameters
expect(Sortable.default.create).toHaveBeenCalledTimes(1);
expect(Sortable.default.create).toHaveBeenCalledWith(
mockElement,
expect.objectContaining({
animation: 100,
delay: 400,
delayOnTouchOnly: true,
...customOptions,
}),
);
});
});

View File

@@ -0,0 +1,36 @@
import type { SortableOptions } from 'sortablejs';
import type Sortable from 'sortablejs';
function useSortable<T extends HTMLElement>(
sortableContainer: T,
options: SortableOptions = {},
) {
const initializeSortable = async () => {
const Sortable = await import(
// @ts-expect-error - This is a dynamic import
'sortablejs/modular/sortable.complete.esm.js'
);
// const { AutoScroll } = await import(
// // @ts-expect-error - This is a dynamic import
// 'sortablejs/modular/sortable.core.esm.js'
// );
// Sortable?.default?.mount?.(AutoScroll);
const sortable = Sortable?.default?.create?.(sortableContainer, {
animation: 100,
delay: 400,
delayOnTouchOnly: true,
...options,
});
return sortable as Sortable;
};
return {
initializeSortable,
};
}
export { useSortable };
export type { Sortable };