mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Use size class (#28)
* Add use-size-class composition * Use size-class composition in components * Remove unnecessary tests * Update readme
This commit is contained in:
@@ -16,46 +16,4 @@ describe('Avatar', () => {
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('tile');
|
||||
});
|
||||
|
||||
describe('Sizes', () => {
|
||||
test('Extra Small', () => {
|
||||
component.setProps({
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-small'));
|
||||
});
|
||||
|
||||
test('Small', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('small'));
|
||||
});
|
||||
|
||||
test('Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('large'));
|
||||
});
|
||||
|
||||
test('Extra Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-large'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<script lang="ts">
|
||||
import { createComponent, computed } from '@vue/composition-api';
|
||||
import parseCSSVar from '../../utils/parse-css-var';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
@@ -18,32 +19,10 @@ export default createComponent({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
...sizeProps
|
||||
},
|
||||
setup(props) {
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
});
|
||||
|
||||
const sizeClass = useSizeClass(props);
|
||||
return { sizeClass };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -74,53 +74,4 @@ describe('Button', () => {
|
||||
|
||||
expect(component.classes()).toContain('loading');
|
||||
});
|
||||
|
||||
describe('Sizes', () => {
|
||||
const component = mount(VButton, {
|
||||
localVue,
|
||||
propsData: {
|
||||
name: 'person'
|
||||
}
|
||||
});
|
||||
|
||||
test('Extra Small', () => {
|
||||
component.setProps({
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-small'));
|
||||
});
|
||||
|
||||
test('Small', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('small'));
|
||||
});
|
||||
|
||||
test('Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('large'));
|
||||
});
|
||||
|
||||
test('Extra Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-large'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<script lang="ts">
|
||||
import { createComponent, reactive, computed, Ref } from '@vue/composition-api';
|
||||
import parseCSSVar from '@/utils/parse-css-var';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
@@ -49,32 +50,10 @@ export default createComponent({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
...sizeProps
|
||||
},
|
||||
setup(props) {
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
});
|
||||
|
||||
const sizeClass = useSizeClass(props);
|
||||
return { sizeClass };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -112,54 +112,4 @@ describe('Chip', () => {
|
||||
|
||||
expect(component.emitted('click')).toBe(undefined);
|
||||
});
|
||||
|
||||
describe('Sizes', () => {
|
||||
const component = mount(VChip, {
|
||||
localVue,
|
||||
propsData: {
|
||||
color: '--blue-grey',
|
||||
name: 'person'
|
||||
}
|
||||
});
|
||||
|
||||
test('Extra Small', () => {
|
||||
component.setProps({
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-small'));
|
||||
});
|
||||
|
||||
test('Small', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('small'));
|
||||
});
|
||||
|
||||
test('Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('large'));
|
||||
});
|
||||
|
||||
test('Extra Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-large'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<script lang="ts">
|
||||
import { createComponent, ref, computed } from '@vue/composition-api';
|
||||
import parseCSSVar from '@/utils/parse-css-var';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
@@ -49,22 +50,7 @@ export default createComponent({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
...sizeProps
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const _localActive = ref(true);
|
||||
@@ -80,13 +66,7 @@ export default createComponent({
|
||||
}
|
||||
});
|
||||
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
});
|
||||
const sizeClass = useSizeClass(props);
|
||||
|
||||
return { sizeClass, _active, onClick, onCloseClick };
|
||||
|
||||
|
||||
@@ -23,78 +23,16 @@ describe('Icon', () => {
|
||||
expect(component.contains('svg')).toBe(true);
|
||||
});
|
||||
|
||||
describe('Sizes', () => {
|
||||
test('Superscript', async () => {
|
||||
component.setProps({
|
||||
sup: true,
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('sup');
|
||||
});
|
||||
|
||||
test('Extra Small', async () => {
|
||||
component.setProps({
|
||||
sup: false,
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('x-small');
|
||||
});
|
||||
|
||||
test('Small', async () => {
|
||||
component.setProps({
|
||||
sup: false,
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('small');
|
||||
});
|
||||
|
||||
test('Large', async () => {
|
||||
component.setProps({
|
||||
sup: false,
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('large');
|
||||
});
|
||||
|
||||
test('Extra Large', async () => {
|
||||
component.setProps({
|
||||
sup: false,
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('x-large');
|
||||
});
|
||||
|
||||
it('Uses the smallest size prop provided (sup)', async () => {
|
||||
component.setProps({
|
||||
sup: true,
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('sup');
|
||||
it('Supports superscript size class', async () => {
|
||||
component.setProps({
|
||||
sup: true,
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect(component.classes()).toContain('sup');
|
||||
});
|
||||
|
||||
it('Adds the has-click class if a click event is passed', async () => {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { createComponent, reactive, computed } from '@vue/composition-api';
|
||||
import parseCSSVar from '@/utils/parse-css-var';
|
||||
import CustomIconBox from './custom-icons/box.vue';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
const customIcons: string[] = ['box'];
|
||||
|
||||
@@ -32,22 +33,6 @@ export default createComponent({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
left: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
@@ -55,17 +40,14 @@ export default createComponent({
|
||||
right: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
...sizeProps
|
||||
},
|
||||
|
||||
setup(props, { emit, listeners }) {
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.sup) return 'sup';
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
return useSizeClass(props).value;
|
||||
});
|
||||
|
||||
const customIconName = computed<string | null>(() => {
|
||||
|
||||
@@ -11,55 +11,7 @@ describe('Spinner', () => {
|
||||
|
||||
beforeEach(() => (component = mount(VSpinner, { localVue })));
|
||||
|
||||
describe('Sizes', () => {
|
||||
test('Extra Small', () => {
|
||||
component.setProps({
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-small'));
|
||||
});
|
||||
|
||||
test('Small', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('small'));
|
||||
});
|
||||
|
||||
test('Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('large'));
|
||||
});
|
||||
|
||||
test('Extra Large', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('x-large'));
|
||||
});
|
||||
|
||||
it('Uses the smallest size prop provided (small)', () => {
|
||||
component.setProps({
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: true
|
||||
});
|
||||
component.vm.$nextTick(() => expect(component.classes()).toContain('small'));
|
||||
});
|
||||
it('Renders', () => {
|
||||
expect(component.exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,35 +5,12 @@
|
||||
<script lang="ts">
|
||||
import { createComponent, computed } from '@vue/composition-api';
|
||||
import parseCSSVar from '@/utils/parse-css-var';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
props: sizeProps,
|
||||
setup(props) {
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
});
|
||||
|
||||
const sizeClass = useSizeClass(props);
|
||||
return { sizeClass };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ Compositions are reusable pieces of logic that can be used inside Vue components
|
||||
## Table of Contents
|
||||
|
||||
* [Event Listener](#event-listener)
|
||||
* [Size Class](#size-class)
|
||||
* [Time from Now](#time-from-now)
|
||||
* [Window Size](#window-size)
|
||||
|
||||
@@ -33,6 +34,29 @@ export default createComponent({
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Size Class
|
||||
|
||||
Shared size class prop handler for base components. Adds `x-small`, `small`, `large`, and `x-large` props to the component, and converts the prop into a string that can be added to classes.
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import { createComponent } from '@vue/composition-api';
|
||||
import useSizeClass, { sizeProps } from '@/compositions/size-class';
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
...sizeProps
|
||||
},
|
||||
setup(props) {
|
||||
const sizeClass = useSizeClass(props);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Time from Now
|
||||
|
||||
@@ -54,6 +78,8 @@ export default createComponent({
|
||||
|
||||
The composition accepts an optional second parameter that controls how often the value is update. You can set this to `0` if you don't want the value to update at all.
|
||||
|
||||
---
|
||||
|
||||
## Window Size
|
||||
|
||||
Returns a `ref` of `width` and `height` of the current window size. Updates the value on window resizes.
|
||||
|
||||
87
src/compositions/size-class.test.ts
Normal file
87
src/compositions/size-class.test.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import VueCompositionAPI, { Ref } from '@vue/composition-api';
|
||||
import useSizeClass from './size-class';
|
||||
import mountComposition from '../../.jest/mount-composition';
|
||||
|
||||
describe('Compositions / Size Class', () => {
|
||||
it('Extracts the correct class based on given props', () => {
|
||||
let props = {
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe(null);
|
||||
}).destroy();
|
||||
|
||||
props = {
|
||||
xSmall: true,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: false,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe('x-small');
|
||||
}).destroy();
|
||||
|
||||
props = {
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: false,
|
||||
xLarge: false,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe('small');
|
||||
}).destroy();
|
||||
|
||||
props = {
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: true,
|
||||
xLarge: false,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe('large');
|
||||
}).destroy();
|
||||
|
||||
props = {
|
||||
xSmall: false,
|
||||
small: false,
|
||||
large: false,
|
||||
xLarge: true,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe('x-large');
|
||||
}).destroy();
|
||||
});
|
||||
|
||||
it('Defaults to the smallest size if multiple sizes are passed', () => {
|
||||
const props = {
|
||||
xSmall: false,
|
||||
small: true,
|
||||
large: true,
|
||||
xLarge: true,
|
||||
ignoredKey: 'test'
|
||||
};
|
||||
|
||||
mountComposition(() => {
|
||||
const className = useSizeClass(props);
|
||||
expect(className.value).toBe('small');
|
||||
}).destroy();
|
||||
});
|
||||
});
|
||||
39
src/compositions/size-class.ts
Normal file
39
src/compositions/size-class.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { computed } from '@vue/composition-api';
|
||||
|
||||
export const sizeProps = {
|
||||
xSmall: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
large: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
xLarge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
};
|
||||
|
||||
interface RequiredProps {
|
||||
xSmall: boolean;
|
||||
small: boolean;
|
||||
large: boolean;
|
||||
xLarge: boolean;
|
||||
}
|
||||
|
||||
export default function useSizeClass<T>(props: T & RequiredProps) {
|
||||
const sizeClass = computed<string | null>(() => {
|
||||
if (props.xSmall) return 'x-small';
|
||||
if (props.small) return 'small';
|
||||
if (props.large) return 'large';
|
||||
if (props.xLarge) return 'x-large';
|
||||
return null;
|
||||
});
|
||||
|
||||
return sizeClass;
|
||||
}
|
||||
Reference in New Issue
Block a user