Skip to content

Commit

Permalink
feat: new directive v-tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
zzxming committed Aug 1, 2024
2 parents f32904a + 68857f5 commit 1c3fecc
Show file tree
Hide file tree
Showing 25 changed files with 2,424 additions and 2,058 deletions.
4 changes: 4 additions & 0 deletions docs/.vitepress/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default defineConfig({
{ text: 'PullRefresh', link: '/component/pull-refresh' },
],
},
{
text: '指令',
items: [{ text: 'vToolTip', link: '/component/v-tooltip' }],
},
],
},
},
Expand Down
13 changes: 13 additions & 0 deletions docs/component/v-tooltip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# vToolTip

## 基础用法

:::demo v-tooltip/base

:::

## 提示位置

:::demo v-tooltip/position

:::
2 changes: 1 addition & 1 deletion docs/demos/collapse/base.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup>
import { ref } from 'vue';
const activeName = ref(['1']);
const activeName = ref([1]);
</script>

<template>
Expand Down
5 changes: 5 additions & 0 deletions docs/demos/v-tooltip/base.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<button v-tooltip="false">
hover
</button>
</template>
16 changes: 16 additions & 0 deletions docs/demos/v-tooltip/position.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div style="position: relative;height: 300px; ">
<button v-tooltip:top="'top tooltip'" style="border: 1px solid; position: absolute; top: 0; left: 50%; transform: translate(-50%, 0);">
hover
</button>
<button v-tooltip:right="'right tooltip'" style="border: 1px solid; position: absolute; top: 50%; right: 0; transform: translate(0, -50%);">
hover
</button>
<button v-tooltip:bottom="'bottom tooltip'" style="border: 1px solid; position: absolute; bottom: 0; left: 50%; transform: translate(-50%, 0);">
hover
</button>
<button v-tooltip:left="'left tooltip'" style="border: 1px solid; position: absolute; top:50%; left: 0; transform: translate(0, -50%);">
hover
</button>
</div>
</template>
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"peerDependencies": {
"vue": "^3.3.11"
},
"dependencies": {
"lodash-unified": "^1.0.3"
},
"devDependencies": {
"@cdx-component/build-utils": "workspace:^",
"@cdx-component/components": "workspace:^",
Expand Down
4 changes: 4 additions & 0 deletions packages/cdx-component/directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { Plugin } from 'vue';
import { CdxVTooltip } from '../directives/tooltip';

export default [CdxVTooltip] as Plugin[]; ;
1 change: 1 addition & 0 deletions packages/cdx-component/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import makeInstall from './makeInstall';

export * from '../components';
export * from '../directives';
export * from '../utils';
export * from '../constants';
export * from '../hooks';
Expand Down
7 changes: 5 additions & 2 deletions packages/cdx-component/makeInstall.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import type { App, Plugin } from '@vue/runtime-core';
import { INSTALLED_KEY } from '../constants';
import Components from './component';
import Directives from './directive';

export const makeInstaller = (components: Plugin[] = []) => {
const install = (app: App) => {
if (app[INSTALLED_KEY]) return;

app[INSTALLED_KEY] = true;
for (const c of components) app.use(c);
for (const c of components) {
app.use(c);
}
};

return {
install,
};
};

export default makeInstaller(Components);
export default makeInstaller([...Components, ...Directives]);
1 change: 1 addition & 0 deletions packages/cdx-component/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const resolveComponent = (name: string) => {
const resolveDirective = async (name: string) => {
const directiveMap: Record<string, any> = {
Loading: {},
Tooltip: {},
};
if (!directiveMap[name]) return;
const partialName = name.toLowerCase();
Expand Down
38 changes: 38 additions & 0 deletions packages/components/collapse/__tests__/collapse.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest';
import { mount } from '@vue/test-utils';
import { nextTick, ref } from 'vue';
import CdxCollapse, { CdxCollapseItem } from '..';

describe('Collapse', () => {
it('switch test', async () => {
const activeName = ref(['1']);
const wrapper = mount(() => (
<CdxCollapse v-model={activeName.value}>
<CdxCollapseItem name="1" title="1">1</CdxCollapseItem>
<CdxCollapseItem name="2" title="2">2</CdxCollapseItem>
</CdxCollapse>
));

const items = wrapper.findAll('.cdx-collapse-item');
expect(items.length).toBe(2);
expect(items[0].find('.cdx-collapse-item__content').text()).toEqual('1');

await items[0].find('.cdx-collapse-item__header').trigger('click');
await items[1].find('.cdx-collapse-item__header').trigger('click');
await nextTick();
expect(items[0].find('.cdx-collapse-item__content').exists()).toBe(false);
expect(items[1].find('.cdx-collapse-item__content').text()).toEqual('2');
});

it('test only item', async () => {
const visible = ref(false);
const wrapper = mount(() => (
<CdxCollapseItem v-model:expend={visible.value} name="1" title="1">1</CdxCollapseItem>
));

expect(wrapper.find('.cdx-collapse-item__content').exists()).toBe(false);
await wrapper.find('.cdx-collapse-item__header').trigger('click');
await nextTick();
expect(wrapper.find('.cdx-collapse-item__content').text()).toBe('1');
});
});
23 changes: 23 additions & 0 deletions packages/components/collapse/__tests__/ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest';
import { renderToString } from '@vue/test-utils';
import { CdxCollapse, CdxCollapseItem } from '..';

describe('SSR for Collapse', () => {
it('render expend', async () => {
try {
const html = await renderToString(
() => (
<CdxCollapse modelValue={['2']}>
<CdxCollapseItem name="1" title="1">content 1</CdxCollapseItem>
<CdxCollapseItem name="2" title="2">content 2</CdxCollapseItem>
</CdxCollapse>
),
);
expect(html).not.toContain('content 1');
expect(html).toContain('content 2');
}
catch (error) {
expect(error).toBeFalsy();
}
});
});
21 changes: 8 additions & 13 deletions packages/components/collapse/src/collapse.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { provide, ref } from 'vue';
import { useBem } from '@cdx-component/hooks';
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@cdx-component/constants';
import { provide } from 'vue';
import { useBem, useModelValue } from '@cdx-component/hooks';
import { CHANGE_EVENT } from '@cdx-component/constants';
import { CollapseModelValueType, collapseEmits, collapseProps } from './collapse';
import { collapseContextKey } from './constants';
Expand All @@ -11,16 +11,10 @@ const emits = defineEmits(collapseEmits);
const [, bem] = useBem('collapse');
const activeNames = ref(props.modelValue);
const setActiveNames = (value: CollapseModelValueType[]) => {
activeNames.value = value;
emits(UPDATE_MODEL_EVENT, value);
emits(CHANGE_EVENT, value);
};
const { model } = useModelValue(props, []);
const handleItemClick = (name: CollapseModelValueType) => {
const _activeNames = [...activeNames.value];
const _activeNames = [...model.value];
const index = _activeNames.indexOf(name);
if (index > -1) {
Expand All @@ -29,11 +23,12 @@ const handleItemClick = (name: CollapseModelValueType) => {
else {
_activeNames.push(name);
}
setActiveNames(_activeNames);
model.value = _activeNames;
emits(CHANGE_EVENT, _activeNames);
};
provide(collapseContextKey, {
activeNames,
activeNames: model,
handleItemClick,
});
</script>
Expand Down
92 changes: 92 additions & 0 deletions packages/components/count-to/__tests__/count-to.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { nextTick, ref } from 'vue';
import CountTo from '..';

vi.mock('@cdx-component/utils/raf', async (importOriginal) => {
const mod = await importOriginal<typeof import('@cdx-component/utils/raf')>();
return {
...mod,
raf: (fn: (t: number) => void) => {
let lastTime = 0;
const currTime = Date.now();
const timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
return setTimeout(() => {
fn(currTime + timeToCall);
lastTime = currTime + timeToCall;
}, timeToCall);
},
caf: (id: number) => clearTimeout(id),
};
});
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});

describe('CounTo.vue', () => {
it('count test', async () => {
const wrapper = mount(() => <CountTo endValue={100} />);
expect(wrapper.html()).toContain('<span class="cdx-count-to">000</span>');
vi.runAllTimers();
await nextTick();
expect(wrapper.html()).toContain('<span class="cdx-count-to">100</span>');
});

it('decimal test', async () => {
const wrapper = mount(() => <CountTo endValue={100} decimal={2} />);
expect(wrapper.html()).toContain('<span class="cdx-count-to">000.00</span>');
vi.runAllTimers();
await nextTick();
expect(wrapper.html()).toContain('<span class="cdx-count-to">100.00</span>');
});

it('test expose', async () => {
const wrapper = mount(() => {
const countRef = ref<InstanceType<typeof CountTo>>();

const stopCount = () => {
countRef.value?.stopCount();
};
const startCount = () => {
countRef.value?.startCount();
};
const reset = () => {
countRef.value?.reset();
};
return (
<>
<button class="pause" onClick={stopCount}>pause</button>
<button class="start" onClick={startCount}>start</button>
<button class="reset" onClick={reset}>reset</button>
<CountTo autoStart={false} ref={countRef} endValue={100} duration={2000} />
</>
);
});
const countComp = wrapper.findComponent(CountTo);
expect(countComp.html()).toContain('<span class="cdx-count-to">000</span>');
await wrapper.find('.start').trigger('click');
vi.advanceTimersByTime(300);
await nextTick();
const num = Number(countComp.text());
expect(num).toBeLessThan(100);
expect(num).toBeGreaterThan(0);

await wrapper.find('.pause').trigger('click');
vi.advanceTimersByTime(300);
await nextTick();
const pausedNum = Number(countComp.text());
expect(pausedNum).toEqual(num);

await wrapper.find('.start').trigger('click');
vi.advanceTimersByTime(2000);
await nextTick();
expect(Number(countComp.text())).toEqual(100);

await wrapper.find('.reset').trigger('click');
await nextTick();
expect(countComp.text()).toEqual('000');
});
});
37 changes: 37 additions & 0 deletions packages/components/count-to/__tests__/ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest';
import { renderToString } from '@vue/test-utils';
import CounTo from '..';

describe('SSR for CounTo', () => {
it('render', async () => {
try {
const html = await renderToString(<CounTo endValue={100} />);
expect(html).toContain('000');
expect(html).toContain('<span class="cdx-count-to">');
}
catch (error) {
expect(error).toBeFalsy();
}
});

it('render slot', async () => {
try {
const html = await renderToString(
<CounTo endValue={100}>
{{
prefix: () => 'P',
suffix: () => 'S',
default: ({ value }: { value: number }) => value,
}}
</CounTo>,
);
expect(html).toContain('P');
expect(html).toContain('0');
expect(html).toContain('S');
expect(html).toContain('<span class="cdx-count-to">');
}
catch (error) {
expect(error).toBeFalsy();
}
});
});
10 changes: 10 additions & 0 deletions packages/components/icon/__tests__/icon.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { mount } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';
import Icon from '..';

describe('Icon.vue', () => {
it('render test', async () => {
const wrapper = mount(() => <Icon>text</Icon>);
expect(wrapper.html()).toContain('<i class="cdx-icon">text</i>');
});
});
16 changes: 16 additions & 0 deletions packages/components/icon/__tests__/ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest';
import { renderToString } from '@vue/test-utils';
import Icon from '..';

describe('SSR for Icon', () => {
it('render', async () => {
try {
const html = await renderToString(<Icon>text</Icon>);
expect(html).toContain('text');
expect(html).toContain('<i class="cdx-icon">');
}
catch (error) {
expect(error).toBeFalsy();
}
});
});
Loading

0 comments on commit 1c3fecc

Please sign in to comment.