Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Commit

Permalink
adds basic design system utils
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianKienle committed Dec 10, 2018
1 parent eacff52 commit 3e7f575
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 8 deletions.
83 changes: 83 additions & 0 deletions src/directives/design-system-utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { directiveName } from '@/util';
import Vue from 'vue';

type Side = keyof {
top: 'top',
right: 'right',
bottom: 'bottom',
left: 'left',
};

const sizeMapping = {none: 'none', tiny: 'tiny', small: 'small', medium: 'medium', large: 'large'};
type Size = keyof typeof sizeMapping;
const Sizes = Object.keys(sizeMapping) as Size[];
const isSize = (value: any): value is Size | undefined => value === undefined || Sizes.includes(value);

type PaddingModifiers = {
top?: boolean; left?: boolean; right?: boolean; bottom?: boolean;
};

type DesignClass = 'padding' | 'margin';

const designClass = (prefix: DesignClass, size: Size, side?: Side) => side == null ? `fd-has-${prefix}-${size}` : `fd-has-${prefix}-${side}-${size}`;
const designClasses = (prefix: DesignClass, size: Size, modifiers: PaddingModifiers = {}): string[] => {
const {top, left, right, bottom} = modifiers;
if(top == null && left == null && right == null && bottom == null) {
return [designClass(prefix, size)];
}
const classes: string[] = [];
if(top === true) { classes.push(designClass(prefix, size, 'top')); }
if(bottom === true) { classes.push(designClass(prefix, size, 'bottom')); }
if(left === true) { classes.push(designClass(prefix, size, 'left')); }
if(right === true) { classes.push(designClass(prefix, size, 'right')); }
return classes;
};
const paddingClasses = (size: Size, modifiers: PaddingModifiers = {}): string[] => designClasses('padding', size, modifiers);
const marginClasses = (size: Size, modifiers: PaddingModifiers = {}): string[] => designClasses('margin', size, modifiers);

/*
Usage:
v-padding:small
v-padding:small.left.right.bottom
^---^ ^---------------^
arg modifiers
*/
export const padding = Vue.directive(directiveName('padding'), ({ classList }, binding) => {
const { arg, modifiers } = binding;
if(!isSize(arg)) { return; }
const size = arg;
classList.add(...paddingClasses(size, modifiers));
});

export const margin = Vue.directive(directiveName('margin'), ({ classList }, binding) => {
const { arg, modifiers } = binding;
if(!isSize(arg)) { return; }
const size = arg;
classList.add(...marginClasses(size, modifiers));
});

type FontWeight = 'light' | 'bold' | 'normal';
const isFontWeight = (value: any): value is FontWeight => value === 'light' || value === 'bold' || value === 'normal';
export const fontWeight = Vue.directive(directiveName('font-weight'), ({ classList }, binding) => {
const { arg } = binding;
if(!isFontWeight(arg)) { return; }
classList.add(`fd-has-font-weight-${arg}`);
});

type FontFamily = 'body' | 'header' | 'code';
const isFontFamily = (value: any): value is FontFamily => ['body', 'header', 'code'].includes(value);
export const fontFamily = Vue.directive(directiveName('font-family'), ({ classList }, binding) => {
const { arg } = binding;
if(!isFontFamily(arg)) { return; }
classList.add(`fd-has-font-family-${arg}`);
});

const typeMapping = { '-1': 'minus-1', '0': '0', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6' };
type Type = keyof typeof typeMapping;
const Types = Object.keys(typeMapping) as Type[];
const isType = (value: any): value is Type => Types.includes(value);
export const type = Vue.directive(directiveName('type'), ({ classList }, binding) => {
const { arg } = binding;
if(!isType(arg)) { return 'fd-has-type'; }
classList.add(`fd-has-type-${typeMapping[arg]}`);
});
18 changes: 18 additions & 0 deletions src/directives/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
import { PluginObject } from 'vue';
import { hasBackgroundColor } from './has-background-color';
import { icon } from './icon';
import { padding, margin, fontWeight, fontFamily } from './design-system-utilities';

export * from './has-background-color';
export * from './icon';
export * from './design-system-utilities';

export default {
install(Vue) {
Vue.directive('bg', hasBackgroundColor);
Vue.directive('hasBackgroundColor', hasBackgroundColor);
Vue.directive('icon', icon);
Vue.directive('padding', padding);
Vue.directive('margin', margin);
Vue.directive('font-weight', fontWeight);
Vue.directive('font-family', fontFamily);
},
} as PluginObject<{}>;
1 change: 0 additions & 1 deletion src/docs/components/ComponentExample/ComponentExample.sass
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
.component-example
padding: 30px 30px 30px 30px
.example-title
font-size: 21px
color: #555555
.example__show_code
color: #aaaaaa
Expand Down
11 changes: 10 additions & 1 deletion src/docs/components/ComponentExample/ComponentExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ export class ComponentExample extends TsxComponent<Props> {

return (
<div class='component-example'>
<h1 class='example-title'>
<h1
class='example-title'
{
...{
directives: [
{name: 'type', arg: '4'},
{name: 'font-weight', arg: 'light'},
]}
}
>
{this.title}
<Button
compact={true}
Expand Down
21 changes: 21 additions & 0 deletions src/docs/pages/Design System Utils/0-margin.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<title>Margin (mixed)</title>
<tip>Supported size classes: `none`, `tiny`, `small`, `medium`, `large`. By default the size is applied to all sides. You can constrain the sides by using the modifiers `top`, `left`, `bottom` and `right`.</tip>
<template>
<div class="container">
<div v-margin:small>
v-margin:small
</div>

<div v-margin:small.top.left>
v-margin:small.top.left
</div>

<div v-margin:small.top.left v-margin:medium.bottom.right>
v-margin:small.top.left v-margin:medium.bottom.right
</div>
</div>
</template>

<style scoped>
.container div { border: 1px solid #cccccc; font-family: monospace; background-color: #efefef; }
</style>
20 changes: 20 additions & 0 deletions src/docs/pages/Design System Utils/1-padding.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<title>Padding (mixed)</title>
<tip>Supported size classes: `none`, `tiny`, `small`, `medium`, `large`. By default the size is applied to all sides. You can constrain the sides by using the modifiers `top`, `left`, `bottom` and `right`.</tip>

<template>
<div class="container">
<div v-padding:small>
v-padding:small
</div>
<div v-padding:small.top.left>
v-padding:small.top.left
</div>
<div v-padding:small.top.left v-padding:medium.bottom.right>
v-padding:small.top.left v-padding:medium.bottom.right
</div>
</div>
</template>

<style scoped>
.container div { font-family: monospace; background-color: #efefef; border: 1px #cccccc solid; margin-block-end: 1rem; }
</style>
17 changes: 17 additions & 0 deletions src/docs/pages/Design System Utils/2-remove-padding.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<title>Removing Padding</title>
<tip>Use `v-padding` multiple times to selectively remove padding.</tip>

<template>
<div class="container">
<div v-padding:medium v-padding:none.left>
v-padding:medium v-padding:none.left
</div>
<div v-padding:medium v-padding:none.left.bottom>
v-padding:medium v-padding:none.left.bottom
</div>
</div>
</template>

<style scoped>
.container div { font-family: monospace; background-color: #efefef; border: 1px #cccccc solid; margin-block-end: 1rem; }
</style>
9 changes: 9 additions & 0 deletions src/docs/pages/Design System Utils/4-font-weight.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<title>Type Weight</title>

<template>
<div>
<p v-font-weight:light>This is font with weight light</p>
<p v-font-weight:normal>This is font with weight normal</p>
<p v-font-weight:bold>This is font with weight bold</p>
</div>
</template>
9 changes: 9 additions & 0 deletions src/docs/pages/Design System Utils/5-font-family.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<title>Type Family</title>

<template>
<div>
<p v-font-family:body>This is body text</p>
<p v-font-family:header>This is header text</p>
<p v-font-family:code>This is code text</p>
</div>
</template>
14 changes: 14 additions & 0 deletions src/docs/pages/Design System Utils/6-font-type.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<title>Type</title>

<template>
<div>
<p v-type:-1>This is text type size -1</p>
<p v-type:0>This is text type size 0</p>
<p v-type:1>This is text type size 1</p>
<p v-type:2>This is text type size 2</p>
<p v-type:3>This is text type size 3</p>
<p v-type:4>This is text type size 4</p>
<p v-type:5>This is text type size 5</p>
<p v-type:6>This is text type size 6</p>
</div>
</template>
3 changes: 3 additions & 0 deletions src/docs/pages/Design System Utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ExampleCollectionFunction } from '../types';

export const plugin: ExampleCollectionFunction = () => ({ experimental: true, icon: 'action' });
1 change: 0 additions & 1 deletion src/docs/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ const requireExampleCollections = (): ExampleCollection[] => {
return title || key;
};
const context = require.context('./', true, /(.*)\/(.+)\/index\.ts$/);

const collectionFromKey = (key: string): ExampleCollection => {
const title = titleFromKey(key);
const slug = slugify(title);
Expand Down
2 changes: 1 addition & 1 deletion src/docs/pages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { VueConstructor } from 'vue';
import { IconName } from '@/lib';

type ExampleCollectionPlugin = {
relatedComponents: VueConstructor[];
relatedComponents?: VueConstructor[];
icon?: IconName;
experimental?: boolean;
};
Expand Down
6 changes: 2 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

import * as components from '@/components';
import { hasBackgroundColor } from '@/directives';
import Directives from '@/directives';
import { VueConstructor, PluginFunction } from 'vue';
import { componentName } from '@/util';

Expand All @@ -13,8 +12,7 @@ const api = {
};

const installFundamentals: PluginFunction<object> = vue /*, options */ => {
vue.directive('bg', hasBackgroundColor);
vue.directive('hasBackgroundColor', hasBackgroundColor);
vue.use(Directives);
components.plugin().install(vue, api);
};
export default installFundamentals;

0 comments on commit 3e7f575

Please sign in to comment.