Skip to content

Commit

Permalink
feat(module)!: use tailwind-merge for class merging (#509)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamincanac committed Sep 7, 2023
1 parent 6d7973f commit 8880bdc
Show file tree
Hide file tree
Showing 47 changed files with 683 additions and 374 deletions.
4 changes: 2 additions & 2 deletions docs/components/color-picker/ColorPickerPill.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<UTooltip :text="color.value" class="capitalize" :open-delay="500">
<UButton
color="gray"
color="transparent"
square
:ui="{
color: {
gray: {
transparent: {
solid: 'bg-gray-100 dark:bg-gray-800',
ghost: 'hover:bg-gray-50 dark:hover:bg-gray-800/50'
}
Expand Down
9 changes: 5 additions & 4 deletions docs/components/content/ComponentCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
v-model="componentProps[prop.name]"
:name="`prop-${prop.name}`"
tabindex="-1"
:ui="{ wrapper: 'relative flex items-start justify-center' }"
class="justify-center"
/>
<USelectMenu
v-else-if="prop.type === 'string' && prop.options.length"
v-model="componentProps[prop.name]"
:options="prop.options"
:name="`prop-${prop.name}`"
variant="none"
:ui-menu="{ width: 'w-32 !-mt-px', rounded: 'rounded-b-md', wrapper: 'relative inline-flex' }"
class="!py-0"
class="inline-flex"
:ui-menu="{ width: 'w-32 !-mt-px', rounded: 'rounded-t-none' }"
select-class="py-0"
tabindex="-1"
:popper="{ strategy: 'fixed', placement: 'bottom-start' }"
/>
Expand All @@ -28,7 +29,7 @@
:name="`prop-${prop.name}`"
variant="none"
autocomplete="off"
class="!py-0"
input-class="py-0"
tabindex="-1"
@update:model-value="val => componentProps[prop.name] = prop.type === 'number' ? Number(val) : val"
/>
Expand Down
2 changes: 1 addition & 1 deletion docs/components/content/examples/FormGroupErrorExample.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<UFormGroup v-slot="{ error }" label="Email" :error="!email && 'You must enter an email'" help="This is a nice email!">
<UInput v-model="email" type="email" placeholder="Enter email" :trailing-icon="error && 'i-heroicons-exclamation-triangle-20-solid'" />
<UInput v-model="email" type="email" placeholder="Enter email" :trailing-icon="error ? 'i-heroicons-exclamation-triangle-20-solid' : undefined" />
</UFormGroup>
</template>

Expand Down
2 changes: 1 addition & 1 deletion docs/components/content/examples/TableExampleAdvanced.vue
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ const { data: todos, pending } = await useLazyAsyncData('todos', () => $fetch<{
:total="pageTotal"
:ui="{
wrapper: 'flex items-center gap-1',
rounded: 'rounded-full min-w-[32px] justify-center',
rounded: '!rounded-full min-w-[32px] justify-center',
default: {
activeButton: {
variant: 'outline'
Expand Down
2 changes: 1 addition & 1 deletion docs/components/content/themes/PaginationThemeRounded.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const items = ref(Array(55))
:total="items.length"
:ui="{
wrapper: 'flex items-center gap-1',
rounded: 'rounded-full min-w-[32px] justify-center'
rounded: '!rounded-full min-w-[32px] justify-center'
}"
:prev-button="null"
:next-button="{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const links = [{
:links="links"
:ui="{
wrapper: 'border-s border-gray-200 dark:border-gray-800 space-y-2',
base: 'group block border-s -ms-px lg:leading-6',
padding: 'ps-4',
base: 'group block border-s -ms-px lg:leading-6 before:hidden',
padding: 'p-0 ps-4',
rounded: '',
font: '',
ring: '',
Expand Down
43 changes: 43 additions & 0 deletions docs/content/1.getting-started/3.theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ This can also happen when you bind a dynamic color to a component: `<UBadge :col

## Components

### `app.config.ts`

Components are styled with Tailwind CSS but classes are all defined in the default [app.config.ts](https://github.com/nuxtlabs/ui/blob/dev/src/runtime/app.config.ts) file. You can override those in your own `app.config.ts`.

```ts [app.config.ts]
Expand All @@ -89,6 +91,8 @@ export default defineAppConfig({
})
```

### `ui` prop

Each component has a `ui` prop that allows you to customize everything specifically.

```vue
Expand All @@ -103,6 +107,45 @@ Each component has a `ui` prop that allows you to customize everything specifica
You can find the default classes for each component under the `Preset` section.
::

Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `ui` prop is smartly merged with the config. This means you don't have to rewrite everything. :u-badge{label="Edge" class="!rounded-full" variant="subtle"}

For example, the default preset of the `FormGroup` component looks like this:

```json
{
...
"label": {
"base": "block font-medium text-gray-700 dark:text-gray-200",
...
}
...
}
```

To change the font of the `label`, you only need to write:

```vue
<UFormGroup name="email" label="Email" :ui="{ label: { base: 'font-semibold' } }">
...
</UFormGroup>
```

This will smartly replace the `font-medium` by `font-semibold` and prevent any class duplication and any class priority issue.

### `class` attribute

You can also use the `class` attribute to add classes to the component.

```vue
<template>
<UButton label="Button" class="rounded-full" />
</template>
```

Again, with [tailwind-merge](https://github.com/dcastil/tailwind-merge), this will smartly merge the classes with the `ui` prop and the config. :u-badge{label="Edge" class="!rounded-full" variant="subtle"}

### Default values

Some component props like `size`, `color`, `variant`, etc. have a default value that you can override in your `app.config.ts`.

```ts [app.config.ts]
Expand Down
6 changes: 3 additions & 3 deletions docs/content/1.getting-started/5.examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ const links = [{
:links="links"
:ui="{
wrapper: 'border-s border-gray-200 dark:border-gray-800 space-y-2',
base: 'group block border-s -ms-px lg:leading-6',
padding: 'ps-4',
base: 'group block border-s -ms-px lg:leading-6 before:hidden',
padding: 'p-0 ps-4',
rounded: '',
font: '',
ring: '',
Expand Down Expand Up @@ -254,7 +254,7 @@ const items = ref(Array(55))
:total="items.length"
:ui="{
wrapper: 'flex items-center gap-1',
rounded: 'rounded-full min-w-[32px] justify-center'
rounded: '!rounded-full min-w-[32px] justify-center'
}"
:prev-button="null"
:next-button="{
Expand Down
2 changes: 0 additions & 2 deletions docs/content/3.forms/9.form-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ baseProps:
props:
label: 'Email'
error: true
ui:
error: 'hidden'
excludedProps:
- ui
- error
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,21 @@
"defu": "^6.1.2",
"fuse.js": "^6.6.2",
"lodash-es": "^4.17.21",
"tailwind-merge": "^1.14.0",
"tailwindcss": "^3.3.3"
},
"devDependencies": {
"@nuxt/eslint-config": "^0.1.1",
"@nuxt/module-builder": "^0.4.0",
"@release-it/conventional-changelog": "^7.0.0",
"eslint": "^8.47.0",
"joi": "^17.9.2",
"nuxt": "^3.6.5",
"release-it": "^16.1.4",
"typescript": "^5.1.6",
"unbuild": "^1.2.1",
"vue-tsc": "^1.8.8",
"yup": "^1.2.0",
"joi": "^17.9.2",
"zod": "^3.21.4"
}
}
35 changes: 16 additions & 19 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/runtime/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ const select = {
}

const selectMenu = {
wrapper: 'relative',
container: 'z-20',
width: 'w-full',
height: 'max-h-60',
Expand Down
15 changes: 11 additions & 4 deletions src/runtime/components/data/Table.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div :class="ui.wrapper">
<div :class="wrapperClass" v-bind="attrs">
<table :class="[ui.base, ui.divide]">
<thead :class="ui.thead">
<tr :class="ui.tr.base">
Expand Down Expand Up @@ -69,8 +69,10 @@
<script lang="ts">
import { ref, computed, defineComponent, toRaw } from 'vue'
import type { PropType } from 'vue'
import { capitalize, orderBy, omit, get } from 'lodash-es'
import { omit, capitalize, orderBy, get } from 'lodash-es'
import { defu } from 'defu'
import { twMerge } from 'tailwind-merge'
import { defuTwMerge } from '../../utils'
import type { Button } from '../../types/button'
import { useAppConfig } from '#imports'
// TODO: Remove
Expand All @@ -84,6 +86,7 @@ function defaultComparator<T> (a: T, z: T): boolean {
}
export default defineComponent({
inheritAttrs: false,
props: {
modelValue: {
type: Array,
Expand Down Expand Up @@ -135,15 +138,17 @@ export default defineComponent({
},
ui: {
type: Object as PropType<Partial<typeof appConfig.ui.table>>,
default: () => appConfig.ui.table
default: () => ({})
}
},
emits: ['update:modelValue'],
setup (props, { emit, attrs }) {
// TODO: Remove
const appConfig = useAppConfig()
const ui = computed<Partial<typeof appConfig.ui.table>>(() => defu({}, props.ui, appConfig.ui.table))
const ui = computed<Partial<typeof appConfig.ui.table>>(() => defuTwMerge({}, props.ui, appConfig.ui.table))
const wrapperClass = computed(() => twMerge(ui.value.wrapper, attrs.class as string))
const columns = computed(() => props.columns ?? Object.keys(omit(props.rows[0] ?? {}, ['click'])).map((key) => ({ key, label: capitalize(key), sortable: false })))
Expand Down Expand Up @@ -235,8 +240,10 @@ export default defineComponent({
}
return {
attrs: omit(attrs, ['class']),
// eslint-disable-next-line vue/no-dupe-keys
ui,
wrapperClass,
// eslint-disable-next-line vue/no-dupe-keys
sort,
// eslint-disable-next-line vue/no-dupe-keys
Expand Down
Loading

0 comments on commit 8880bdc

Please sign in to comment.