Skip to content

Commit

Permalink
feat: tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
jaskang committed Jun 1, 2023
1 parent 590d7f6 commit f343e59
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 51 deletions.
79 changes: 79 additions & 0 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
computed,
defineComponent,
type ExtractPropTypes,
type ExtractPublicPropTypes,
type PropType,
type SlotsType,
type VNode,
} from 'vue'
import { useStyle } from './style'
import { useTheme } from '@/theme'

const props = {
variant: {
type: String as PropType<'solid' | 'soft' | 'outline' | 'link' | 'subtle'>,
default: 'solid',
},
color: {
type: String as PropType<'primary' | 'success' | 'warning' | 'error' | ColorKey>,
},
size: {
type: String as PropType<'xs' | 'sm' | 'md' | 'lg' | 'xl'>,
default: 'md',
},
ring: {
type: Boolean,
default: true,
},
rounded: Boolean,
square: Boolean,
circle: Boolean,
block: Boolean,
loading: Boolean,
disabled: Boolean,
}

export type ButtonProps = ExtractPropTypes<typeof props>

export type ButtonPublicProps = ExtractPublicPropTypes<typeof props>

export type ButtonCssVars = {
'--t-btn-text-color': string
'--t-btn-text-color-hover': string
'--t-btn-border-color': string
'--t-btn-border-color-hover': string
'--t-btn-bg': string
'--t-btn-bg-hover': string
'--t-btn-ring-color': string
}

export const Button = defineComponent({
name: 'TButton',
props,
emits: {
click: (payload: MouseEvent) => {},
},
slots: Object as SlotsType<{
default: () => VNode
item: { data: number }
}>,
setup(props, { slots, emit }) {
const { getColorKey } = useTheme()

const { cssVars, cls } = useStyle(() => {
return {
...props,
rounded: props.rounded || props.circle,
square: props.square || props.circle,
}
})

const hasIcon = computed(() => !!slots.icon || props.loading)
const onClick = (e: MouseEvent) => {
if (!props.disabled) {
emit('click', e)
}
}
},
})
104 changes: 104 additions & 0 deletions src/components/Button/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { classed, type VariantProps } from '@tw-classed/core'
import { computed, toValue, type MaybeRefOrGetter, toRef, type Ref } from 'vue'
import type { ButtonCssVars, ButtonProps } from './Button'
import { useTheme, type ColorKey } from '@/theme'
import { COLORS } from '@/theme'

const createCssVars = (vars: Partial<ButtonCssVars> = {}) => {
const result: ButtonCssVars = {
'--t-btn-text-color': vars['--t-btn-text-color'] || COLORS.gray[700],
'--t-btn-text-color-hover': vars['--t-btn-text-color-hover'] || vars['--t-btn-text-color'] || COLORS.gray[700],
'--t-btn-border-color': vars['--t-btn-border-color'] || COLORS.transparent,
'--t-btn-border-color-hover':
vars['--t-btn-border-color-hover'] || vars['--t-btn-border-color'] || COLORS.transparent,
'--t-btn-bg': vars['--t-btn-bg'] || COLORS.white,
'--t-btn-bg-hover': vars['--t-btn-bg-hover'] || vars['--t-btn-bg'] || COLORS.white,
'--t-btn-ring-color': vars['--t-btn-ring-color'] || vars['--t-btn-bg'] || COLORS.indigo[500],
}
return result
}

const getBtnCssVars = (variant: ButtonProps['variant'], _color?: ColorKey) => {
if (variant === 'link') {
const color = _color || 'gray'
return createCssVars({
'--t-btn-text-color': COLORS[color][600],
'--t-btn-text-color-hover': COLORS[color][700],
'--t-btn-bg': 'transparent',
})
} else if (variant === 'subtle') {
const color = _color || 'gray'
return createCssVars({
'--t-btn-text-color': COLORS[color][600],
'--t-btn-bg': COLORS[color][100],
'--t-btn-bg-hover': COLORS[color][200],
'--t-btn-ring-color': COLORS[color][500],
})
} else {
const color = _color
return color
? createCssVars({
'--t-btn-text-color': COLORS.white,
'--t-btn-bg': COLORS[color][500],
'--t-btn-border-color': COLORS.transparent,
'--t-btn-bg-hover': COLORS[color][600],
'--t-btn-ring-color': COLORS[color][500],
})
: createCssVars({
'--t-btn-border-color': COLORS.gray[300], // border.default
'--t-btn-bg-hover': COLORS.gray[50],
'--t-btn-ring-color': COLORS.indigo[500],
})
}
}

const createBtnCls = classed('t-button', {
base: `inline-flex text-center justify-center items-center border font-medium
h-[--t-btn-h]
bg-[--t-btn-bg] text-[--t-btn-text-color] border-[--t-btn-border-color]
focus:outline-none
`.replace(/\s+/g, ' '),
variants: {
variant: {
solid: `shadow-sm`,
soft: `shadow-sm`,
outline: `shadow-sm`,
link: ``,
subtle: `shadow-sm`,
},
size: {
xs: '[--t-btn-h:calc(1.75rem+2px)] h-[--t-btn-h] text-xs/3 px-2',
sm: '[--t-btn-h:calc(2rem+2px)] h-[--t-btn-h] text-xs/4 px-3',
md: '[--t-btn-h:calc(2.25rem+2px)] h-[--t-btn-h] text-sm/5 px-4',
lg: '[--t-btn-h:calc(2.5rem+2px)] h-[--t-btn-h] text-base/6 px-5',
xl: '[--t-btn-h:calc(2.75rem+2px)] h-[--t-btn-h] text-base/7 px-6',
},
ring: {
true: 'focus:ring-[--t-btn-ring-color] focus:ring-2 focus:ring-offset-2',
false: 'focus-visible:ring-[--t-btn-ring-color] focus-visible:ring-2 focus-visible:ring-offset-2',
},
rounded: {
true: 'rounded-full',
false: 'rounded-md',
},
square: {
true: '!px-0 w-[--t-btn-h]',
},
block: {
true: 'w-full',
},
disabled: {
true: 'cursor-not-allowed opacity-50',
false: `cursor-pointer hover:bg-[--t-btn-bg-hover] hover:text-[--t-btn-text-color-hover] hover:border-[--t-btn-border-color-hover]`,
},
},
})

export function useStyle(variant: MaybeRefOrGetter<ButtonProps>) {
const { getColorKey } = useTheme()
const variantRef = computed(() => toValue(variant))
return {
cssVars: computed(() => getBtnCssVars(variantRef.value.variant, getColorKey(variantRef.value.color || 'gray'))),
cls: computed(() => createBtnCls(variantRef.value)),
}
}
10 changes: 0 additions & 10 deletions src/components/Button/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@ import { classed, type VariantProps } from '@tw-classed/core'
import { colors, type ColorKey, border } from '@/core/colors'
import { computed, toValue, type MaybeRefOrGetter, toRef } from 'vue'

export type ButtonCssVars = {
'--t-btn-text-color': string
'--t-btn-text-color-hover': string
'--t-btn-border-color': string
'--t-btn-border-color-hover': string
'--t-btn-bg': string
'--t-btn-bg-hover': string
'--t-btn-ring-color': string
}

const createBtnVars = (vars: Partial<ButtonCssVars> = {}) => {
const result: ButtonCssVars = {
'--t-btn-text-color': vars['--t-btn-text-color'] || colors.gray[700],
Expand Down
2 changes: 1 addition & 1 deletion src/components/CheckBox/CheckBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { colors } from '@/core/colors'
import { useTheme } from '@/core/theme'
import { useControllable } from '@/hooks/controllable'
import { ref, computed } from 'vue'
import { ref, computed, type Component } from 'vue'
import { getCssVars } from './styles'
defineOptions({ name: 'TCheckBox' })
Expand Down
34 changes: 0 additions & 34 deletions src/core/theme.ts

This file was deleted.

8 changes: 8 additions & 0 deletions src/styles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@


export function useCssVars<T extends string>('Radio',()=>{
return {
'--t-radio-accent-color': string
'--t-radio-ring-color': string
}
})
14 changes: 8 additions & 6 deletions src/core/colors.ts → src/theme/colors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type ColorAlias = 'primary' | 'success' | 'warning' | 'error'

export type ColorKey =
| 'slate'
| 'gray'
Expand All @@ -21,10 +23,13 @@ export type ColorKey =
| 'fuchsia'
| 'pink'
| 'rose'

export type Color = ColorKey | ColorAlias
export type ColorLv = '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | '950'
export type ColorName = `${ColorKey}.${ColorLv}`
export type ColorPath = `${Color}.${ColorLv}`
export type ColorMap = Record<ColorLv, string>

export const colors = {
export const COLORS = {
transparent: 'transparent',
black: '#000',
white: '#fff',
Expand Down Expand Up @@ -316,9 +321,6 @@ export const colors = {
},
} as const

export const transparent = colors.transparent
export const black = colors.black
export const white = colors.white
export const border = {
default: colors.gray[300],
default: COLORS.gray[300],
}
40 changes: 40 additions & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { computed, ref } from 'vue'
import { type ColorKey, COLORS, type ColorAlias, type ColorMap, type Color } from './colors'

export { COLORS, type ColorKey }

export type Theme = {
colors: {
[key in ColorAlias]: ColorKey
}
}

export function useTheme() {
const theme = ref<Theme>({
colors: {
primary: 'indigo',
success: 'green',
warning: 'amber',
error: 'red',
},
})

const aliasColors = computed(() =>
(Object.keys(theme.value.colors) as ColorAlias[]).reduce((acc, alias) => {
acc[alias] = COLORS[theme.value.colors[alias]]
return acc
}, {} as { [key in ColorAlias]: ColorMap })
)

const getColorKey = (color: Color) => {
// @ts-ignore
return (theme.value.colors[color] || color) as ColorKey
}
const colors = computed(() => {
return {
...COLORS,
...aliasColors.value,
}
})
return { colors, getColorKey }
}
4 changes: 4 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ export const PropTypes = {
string,
symbol,
}

export function emitFn<T extends (...args: any[]) => any>(fn: T) {
return fn as (...args: Parameters<T>) => void
}
Empty file added src/utils/style.ts
Empty file.

0 comments on commit f343e59

Please sign in to comment.