Compare commits

...

43 Commits

Author SHA1 Message Date
Benjamin Canac
b654c93e93 chore(release): v2.20.0 2024-12-09 12:30:42 +01:00
renovate[bot]
b7e04db645 chore(deps): lock file maintenance (dev) (#2862)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 10:18:14 +01:00
renovate[bot]
e6034a2765 chore(deps): update pnpm to v9.15.0 (dev) (#2847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 10:17:34 +01:00
renovate[bot]
a8c38224c6 chore(deps): update devdependency @nuxt/test-utils to ^3.15.1 (dev) (#2838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-07 00:55:49 +01:00
renovate[bot]
a9ef6406ea chore(deps): update all non-major dependencies (dev) (#2819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 12:59:41 +01:00
renovate[bot]
96e846ddee chore(deps): update dependency tailwindcss to ^3.4.16 (dev) (#2830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 13:41:45 +01:00
Benjamin Canac
16dbc1b536 docs(app): remove banner 2024-12-03 10:54:25 +01:00
Benjamin Canac
c6b2ae45e5 docs(Header): hide color mode button on mobile 2024-12-03 10:54:19 +01:00
renovate[bot]
547c657ee7 chore(deps): lock file maintenance (dev) (#2817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 11:18:30 +01:00
renovate[bot]
b16b434041 chore(deps): update all non-major dependencies (dev) (#2756)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-12-02 10:56:20 +01:00
Benjamin Canac
fb12323304 docs(Header): move dropdown out of link 2024-11-30 11:48:03 +01:00
Benjamin Canac
0a404615ff docs(Header): replace badge by dropdown 2024-11-30 11:33:09 +01:00
renovate[bot]
cbf0f22efd chore(deps): update vueuse monorepo to v12 (dev) (major) (#2783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 12:11:47 +01:00
Sandro Circi
4cde571e38 fix(Link): exactQuery prop type (#2781) 2024-11-27 09:47:39 +01:00
Benjamin Canac
023497d144 chore(README): update 2024-11-26 15:18:27 +01:00
Benjamin Canac
56d4ca3b74 docs(Header): update GitHub link 2024-11-26 15:09:10 +01:00
Harsh Patel
11b8c3d9db feat(Notification): add pauseTimeoutOnHover prop (#2661) 2024-11-25 22:09:40 +01:00
Hans Knöchel
419a24f703 feat(Accordion): add close event (#2750) 2024-11-25 14:58:30 +01:00
renovate[bot]
854bb81295 chore(deps): lock file maintenance (dev) (#2751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-11-25 12:54:17 +01:00
Benjamin Canac
bf8e3954a4 docs(Banner): update for black friday 2024-11-25 12:26:31 +01:00
renovate[bot]
637ec4d27b chore(deps): update all non-major dependencies (dev) (#2704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 11:27:00 +01:00
kyyy
f3632ddee5 fix(Form)!: resolve async validation in yup & issue directly mutate state (#2701) 2024-11-23 19:29:54 +01:00
Jevin
dbd2aed20b docs(table): columns select is obscured (#2714) 2024-11-21 11:19:37 +01:00
Giorgio Boa
51c8b8e3e5 fix(components): replace as const with correct type in config (#2652)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-11-20 10:54:37 +01:00
renovate[bot]
588a908358 chore(deps): update all non-major dependencies (dev) (#2693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 10:21:06 +01:00
renovate[bot]
d692a81b1e chore(deps): update nuxt framework to ^3.14.1592 (dev) (#2699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 09:52:12 +01:00
Daniel Roe
ec98d415b4 docs: remove local module from list (#2690) 2024-11-19 18:24:40 +01:00
renovate[bot]
c80d2e6c12 chore(deps): lock file maintenance (dev) (#2671)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 11:40:14 +01:00
renovate[bot]
ce61a2b6db chore(deps): update all non-major dependencies (dev) (#2641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 10:50:58 +01:00
Benjamin Canac
eee5bb9939 chore(deps): set chokidar resolution 2024-11-18 09:35:35 +01:00
Benjamin Canac
d3804157ec docs(input): correct loading behavior
Resolves nuxt/ui#2669
2024-11-18 09:35:23 +01:00
Sandro Circi
03e24f4583 feat(Link): allow partial query match for activeClass (#2663) 2024-11-17 12:15:22 +01:00
jcahal
d0e626c551 docs(table): correct spelling of contextmenu right-clickable (#2653) 2024-11-15 17:32:37 +01:00
renovate[bot]
670d8bfbac chore(deps): update dependency tailwindcss to ^3.4.15 (dev) (#2648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 09:47:28 +01:00
renovate[bot]
64b703df8d chore(deps): update dependency @nuxt/icon to ^1.7.5 (dev) (#2638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 16:45:31 +01:00
Julien Blatecky
976b03f241 fix(types): improve DeepPartial type for App Config (#2621) 2024-11-14 10:33:26 +01:00
renovate[bot]
35e3b8c720 chore(deps): update all non-major dependencies (dev) (#2628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 10:16:36 +01:00
Benjamin Canac
07ef771b17 fix(Carousel): wrong ui type with strategy 2024-11-13 21:02:00 +01:00
Maxime Pauvert
5c75b5c490 docs(Banner): wrong aria label (#2632) 2024-11-13 17:53:50 +01:00
kyyy
53df9d9a8c feat(InputMenu/SelectMenu): add support for dot notation in by prop (#2607) 2024-11-13 12:25:31 +01:00
Malik-Jouda
0d1a76e3c6 feat(Badge): handle icon prop (#2594)
Co-authored-by: malik jouda <m.jouda@approved.tech>
2024-11-12 16:16:20 +01:00
renovate[bot]
b2ed4662af chore(deps): update devdependency @release-it/conventional-changelog to ^9.0.3 (dev) (#2604)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 16:07:30 +01:00
Benjamin Canac
423c48879d chore(github): update issue templates 2024-11-12 13:11:09 +01:00
45 changed files with 2425 additions and 2380 deletions

View File

@@ -29,11 +29,20 @@ body:
- Build Modules: `-` - Build Modules: `-`
validations: validations:
required: true required: true
- type: dropdown
id: package
attributes:
label: Is this bug related to Nuxt or Vue?
options:
- Nuxt
- Vue
validations:
required: true
- type: input - type: input
id: version id: version
attributes: attributes:
label: Version label: Version
placeholder: v3.0.0-alpha.5 placeholder: v3.0.0-alpha.x
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -12,7 +12,7 @@ body:
label: For what version of Nuxt UI are you suggesting this? label: For what version of Nuxt UI are you suggesting this?
options: options:
- v2.x - v2.x
- v3-alpha - v3.0.0-alpha.x
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -12,7 +12,7 @@ body:
label: For what version of Nuxt UI are you asking this question? label: For what version of Nuxt UI are you asking this question?
options: options:
- v2.x - v2.x
- v3-alpha - v3.0.0-alpha.x
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -1,5 +1,38 @@
# Changelog # Changelog
## [2.20.0](https://github.com/nuxt/ui/compare/v2.19.2...v2.20.0) (2024-12-09)
### ⚠ BREAKING CHANGES
* **Form:** resolve async validation in yup & issue directly mutate state (#2701)
### Features
* **Accordion:** add `close` event ([#2750](https://github.com/nuxt/ui/issues/2750)) ([419a24f](https://github.com/nuxt/ui/commit/419a24f7034cefda2c6669f3c26742552e500f63))
* **Badge:** handle `icon` prop ([#2594](https://github.com/nuxt/ui/issues/2594)) ([0d1a76e](https://github.com/nuxt/ui/commit/0d1a76e3c69e08534abb295b96548e67cfbea00c))
* **InputMenu/SelectMenu:** add support for `dot notation` in `by` prop ([#2607](https://github.com/nuxt/ui/issues/2607)) ([53df9d9](https://github.com/nuxt/ui/commit/53df9d9a8cd6850803bdafc7ef6efe4e7404d334))
* **Link:** allow partial query match for `activeClass` ([#2663](https://github.com/nuxt/ui/issues/2663)) ([03e24f4](https://github.com/nuxt/ui/commit/03e24f45836bdddd94b30cbaecc2288a78b56b0b))
* **Notification:** add `pauseTimeoutOnHover` prop ([#2661](https://github.com/nuxt/ui/issues/2661)) ([11b8c3d](https://github.com/nuxt/ui/commit/11b8c3d9db1ec62b1c3557703c7ab5c99cb42df5))
* **Table:** add contextmenu handling to table rows ([#2283](https://github.com/nuxt/ui/issues/2283)) ([c9e6256](https://github.com/nuxt/ui/commit/c9e6256e7f2c06da8bfda13700f56f6994e76eab))
* **Table:** add custom `[@select](https://github.com/select):all` event ([#2581](https://github.com/nuxt/ui/issues/2581)) ([ac323c4](https://github.com/nuxt/ui/commit/ac323c4cccd930f2cd8c1f54b325bd509acd40bf))
* **Table:** allow dynamically render `checkbox` ([#2549](https://github.com/nuxt/ui/issues/2549)) ([d6daf46](https://github.com/nuxt/ui/commit/d6daf466ace42b828151c45b18cd47179e85d66d))
### Bug Fixes
* **AvatarGroup/ButtonGroup/MeterGroup:** allow deeply partial `ui` config ([#2542](https://github.com/nuxt/ui/issues/2542)) ([bf58086](https://github.com/nuxt/ui/commit/bf580863af11d6a1a4c6c6774b44ec37b082e933))
* **Carousel:** wrong `ui` type with `strategy` ([07ef771](https://github.com/nuxt/ui/commit/07ef771b17c72e275508a273371454a5e8a62257))
* **components:** replace `as const` with correct type in config ([#2652](https://github.com/nuxt/ui/issues/2652)) ([51c8b8e](https://github.com/nuxt/ui/commit/51c8b8e3e59d7eceff72625650a199fcf7c6feca))
* **date-picker:** undefined `dayIndex` ([#2545](https://github.com/nuxt/ui/issues/2545)) ([ce955d2](https://github.com/nuxt/ui/commit/ce955d24f1dfd222e87ce88428c0612c3f13cd50))
* **Form:** resolve async validation in yup & issue directly mutate state ([#2701](https://github.com/nuxt/ui/issues/2701)) ([f3632dd](https://github.com/nuxt/ui/commit/f3632ddee511f0fccb24d4fc37403421e84ffdae))
* **Form:** use parsed value from `joi` instead of original state ([#2587](https://github.com/nuxt/ui/issues/2587)) ([acecff4](https://github.com/nuxt/ui/commit/acecff40ec0156e45b4934c5d10c4dfa7c135f8e))
* **InputMenu/SelectMenu:** use `by` prop to compare objects & support dot notation in `value-attribute` ([#2566](https://github.com/nuxt/ui/issues/2566)) ([7154254](https://github.com/nuxt/ui/commit/7154254ac22830f651ec200f7f3af2f5577f2de0))
* **Link:** `exactQuery` prop type ([#2781](https://github.com/nuxt/ui/issues/2781)) ([4cde571](https://github.com/nuxt/ui/commit/4cde571e387775a9b12759f6f8c99117c84cbcff))
* **Notification:** element renders even when no `notification` is present ([#2561](https://github.com/nuxt/ui/issues/2561)) ([d4e408c](https://github.com/nuxt/ui/commit/d4e408cfd8e2ef26021519f2f30f57e9120e1939))
* **Table:** data outdated when rows change ([#2600](https://github.com/nuxt/ui/issues/2600)) ([b23f2de](https://github.com/nuxt/ui/commit/b23f2decfc9607555a315d0d087d0a042f03a938))
* **Table:** missing type on props `loadingState` ([#2551](https://github.com/nuxt/ui/issues/2551)) ([6e66990](https://github.com/nuxt/ui/commit/6e66990372ef6bd7c109a64c753d9b50e96a450b))
* **Table:** prevent `onClick` while blocking element ([#2592](https://github.com/nuxt/ui/issues/2592)) ([9703786](https://github.com/nuxt/ui/commit/97037864b39749db228fa5f51981f19e4a9c29dd))
* **types:** improve `DeepPartial` type for App Config ([#2621](https://github.com/nuxt/ui/issues/2621)) ([976b03f](https://github.com/nuxt/ui/commit/976b03f241ef9626a6338685e43c844a8b3953fd))
## [2.19.2](https://github.com/nuxt/ui/compare/v2.19.1...v2.19.2) (2024-11-05) ## [2.19.2](https://github.com/nuxt/ui/compare/v2.19.1...v2.19.2) (2024-11-05)
### Bug Fixes ### Bug Fixes

View File

@@ -1,4 +1,4 @@
[![nuxt-ui.png](https://repository-images.githubusercontent.com/428329515/43fec891-9030-4601-8233-5d45ba5c6013)](https://ui.nuxt.com) [![nuxt-ui.png](https://volta.s3.fr-par.scw.cloud/nuxt_ui_social_card_531d133fa2.png)](https://ui.nuxt.com)
# Nuxt UI # Nuxt UI

View File

@@ -3,7 +3,7 @@
<div> <div>
<NuxtLoadingIndicator /> <NuxtLoadingIndicator />
<Banner v-if="!$route.path.startsWith('/examples')" /> <!-- <Banner v-if="!$route.path.startsWith('/examples')" /> -->
<Header v-if="!$route.path.startsWith('/examples')" :links="links" /> <Header v-if="!$route.path.startsWith('/examples')" :links="links" />

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
const id = 'nuxt-ui-banner-2' const id = 'nuxt-ui-banner-3'
const to = 'https://ui3.nuxt.dev' const to = '/pro/pricing'
const hideBanner = () => { const hideBanner = () => {
localStorage.setItem(id, 'true') localStorage.setItem(id, 'true')
@@ -28,9 +28,8 @@ if (import.meta.server) {
<NuxtLink <NuxtLink
v-if="to" v-if="to"
:to="to" :to="to"
target="_blank"
class="focus:outline-none" class="focus:outline-none"
aria-label="Nuxt UI Pro pricing" aria-label="20% off on all Nuxt UI Pro products for Black Friday week"
tabindex="-1" tabindex="-1"
> >
<span class="absolute inset-0 " aria-hidden="true" /> <span class="absolute inset-0 " aria-hidden="true" />
@@ -40,19 +39,19 @@ if (import.meta.server) {
<div class="lg:flex-1 hidden lg:flex items-center" /> <div class="lg:flex-1 hidden lg:flex items-center" />
<p class="text-sm font-medium text-white dark:text-gray-900 truncate"> <p class="text-sm font-medium text-white dark:text-gray-900 truncate">
<UIcon name="i-heroicons-rocket-launch" class="w-5 h-5 align-top flex-shrink-0 pointer-events-none mr-2" /> <UIcon name="i-ri-discount-percent-fill" class="size-5 align-top flex-shrink-0 pointer-events-none mr-2" />
<span class="font-semibold">Nuxt UI v3-alpha</span> has been released! <span class="font-bold">Black Friday Week</span>: <UBadge label="20% off" color="white" class="ring-0 font-semibold" /> on all Nuxt UI Pro products from <span class="font-semibold">Nov 25</span> to <span class="font-semibold">Dec 2</span>!
</p> </p>
<UButton <!-- <UButton
to="https://ui3.nuxt.dev" :to="to"
target="_blank" target="_blank"
label="Try it out" label="Buy now"
color="black" color="black"
variant="solid" variant="solid"
size="2xs" size="2xs"
trailing-icon="i-heroicons-arrow-right-20-solid" trailing-icon="i-heroicons-arrow-right-20-solid"
/> /> -->
<div class="flex items-center justify-end lg:flex-1"> <div class="flex items-center justify-end lg:flex-1">
<button <button

View File

@@ -10,12 +10,34 @@
}" }"
> >
<template #left> <template #left>
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-gray-900 dark:text-white min-w-0" aria-label="Nuxt UI"> <NuxtLink to="/" class="flex items-end gap-2 text-xl text-gray-900 dark:text-white min-w-0 shrink-0" aria-label="Nuxt UI">
<LogoPro v-if="$route.path.startsWith('/pro')" class="w-auto h-6 shrink-0" /> <LogoPro v-if="$route.path.startsWith('/pro')" class="w-auto h-6 shrink-0" />
<Logo v-else class="w-auto h-6 shrink-0" /> <Logo v-else class="w-auto h-6 shrink-0" />
<UBadge :label="$route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`" variant="subtle" size="xs" class="-mb-[2px] rounded font-semibold truncate hidden sm:inline-flex" />
</NuxtLink> </NuxtLink>
<UDropdown
:items="[[{ label: $route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`, class: 'text-primary-500 dark:text-primary-400' }, { label: 'v3.0.0-alpha.x', to: 'https://ui3.nuxt.dev' }]]"
:popper="{ strategy: 'absolute', offsetDistance: 11, placement: 'bottom-start' }"
:ui="{
background: 'dark:bg-gray-900',
ring: 'dark:ring-gray-800',
width: 'w-auto',
item: {
padding: 'p-1',
size: 'text-xs',
active: 'dark:bg-gray-800/50'
}
}"
>
<UButton
:label="$route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`"
trailing-icon="i-lucide-chevron-down"
variant="outline"
size="2xs"
truncate
class="-mb-[6px] font-semibold rounded-full truncate ring-primary-500/25 dark:ring-primary-400/25 bg-primary-500/10 dark:bg-primary-400/10 hover:bg-primary-500/15 dark:hover:bg-primary-400/15 transition-colors"
/>
</UDropdown>
</template> </template>
<template #right> <template #right>
@@ -25,10 +47,10 @@
<UContentSearchButton :label="null" /> <UContentSearchButton :label="null" />
</UTooltip> </UTooltip>
<UColorModeButton /> <UColorModeButton class="hidden lg:inline-flex" />
<UButton <UButton
to="https://github.com/nuxt/ui" to="https://github.com/nuxt/ui/tree/dev"
target="_blank" target="_blank"
icon="i-simple-icons-github" icon="i-simple-icons-github"
aria-label="GitHub" aria-label="GitHub"

View File

@@ -45,7 +45,7 @@ const ui = {
inactive: 'text-gray-400 dark:text-gray-500' inactive: 'text-gray-400 dark:text-gray-500'
}, },
avatar: { avatar: {
size: '2xs' as const size: '2xs'
} }
} }
} }

View File

@@ -141,6 +141,74 @@ Badge
You can customize the whole [preset](#preset) by using the `ui` prop. You can customize the whole [preset](#preset) by using the `ui` prop.
:: ::
### Icon
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position.
::component-card
---
props:
icon: 'i-heroicons-rocket-launch'
size: 'sm'
color: 'primary'
variant: 'solid'
label: Badge
trailing: false
options:
- name: variant
restriction: only
values:
- solid
excludedProps:
- icon
- label
---
::
## Slots
### `leading`
Use the `#leading` slot to set the content of the leading icon.
::component-card
---
slots:
leading: <UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" />
baseProps:
color: 'gray'
props:
label: Badge
color: 'gray'
excludedProps:
- color
---
#leading
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs"}
::
### `trailing`
Use the `#trailing` slot to set the content of the trailing icon.
::component-card
---
slots:
trailing: <UIcon name="i-heroicons-rocket-launch" class="w-4 h-4" />
props:
label: Badge
color: 'gray'
excludedProps:
- color
---
#trailing
:u-icon{name="i-heroicons-rocket-launch" class="w-4 h-4"}
::
## Props ## Props
:component-props :component-props

View File

@@ -142,7 +142,7 @@ props:
### Loading ### Loading
Use the `loading` prop to show a loading icon and disable the Input. Use the `loading` prop to show a loading icon in the Input.
Use the `loading-icon` prop to set a different icon or change it globally in `ui.input.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`. Use the `loading-icon` prop to set a different icon or change it globally in `ui.input.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.

View File

@@ -14,6 +14,7 @@ The Link component is a wrapper around [`<NuxtLink>`](https://nuxt.com/docs/api/
- `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active. - `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active.
- `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route. - `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route.
- `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash. - `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash.
- use `exact-query="partial"` to style with `active-class` when the link is active and the query partially match the current query.
The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide. The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide.

View File

@@ -137,9 +137,9 @@ excludedProps:
### Timeout ### Timeout
Use the `timeout` prop to configure how long the Notification will remain. The default value is `5000`, set it to `0` to disable the timeout. Use the `timeout` prop to configure how long the Notification will remain. The default value is `5000`, set it to `0` to disable the timeout. The `pauseTimeoutOnHover` prop (`true` by default) controls whether hovering the notification should pause the timeout.
You will see a progress bar at the bottom of the Notification which will indicate the remaining time. When hovering the Notification, the progress bar will be paused. You will see a progress bar at the bottom of the Notification which will indicate the remaining time. When hovering the Notification, the progress bar will be paused if `pauseTimeoutOnHover` is enabled; otherwise, it won't stop.
::component-card ::component-card
--- ---
@@ -149,6 +149,7 @@ baseProps:
description: 'This is a notification.' description: 'This is a notification.'
props: props:
timeout: 60000 timeout: 60000
pauseTimeoutOnHover: true
--- ---
:: ::

View File

@@ -62,7 +62,7 @@ extraClass: 'overflow-hidden'
padding: false padding: false
component: 'table-example-columns-selectable' component: 'table-example-columns-selectable'
componentProps: componentProps:
class: 'flex-1 flex-col overflow-hidden' class: 'flex-1 flex-col overflow-hidden min-h-[230px]'
--- ---
:: ::
@@ -346,7 +346,7 @@ componentProps:
### Contextmenu ### Contextmenu
Use the `contextmenu` listener on your Table to make the rows righ-clickable. The function will receive the original event as the first argument and the row as the second argument. Use the `contextmenu` listener on your Table to make the rows right-clickable. The function will receive the original event as the first argument and the row as the second argument.
You can use this to open a [ContextMenu](/components/context-menu) for that row. You can use this to open a [ContextMenu](/components/context-menu) for that row.

View File

@@ -27,8 +27,7 @@ export default defineNuxtConfig({
'@nuxtjs/plausible', '@nuxtjs/plausible',
'@vueuse/nuxt', '@vueuse/nuxt',
'nuxt-component-meta', 'nuxt-component-meta',
'nuxt-cloudflare-analytics', 'nuxt-cloudflare-analytics'
'modules/content-examples-code'
], ],
site: { site: {

View File

@@ -4,27 +4,27 @@
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@iconify-json/heroicons": "^1.2.1", "@iconify-json/heroicons": "^1.2.1",
"@iconify-json/simple-icons": "^1.2.11", "@iconify-json/simple-icons": "^1.2.14",
"@iconify-json/vscode-icons": "^1.2.2", "@iconify-json/vscode-icons": "^1.2.3",
"@nuxt/content": "^2.13.4", "@nuxt/content": "^2.13.4",
"@nuxt/fonts": "^0.10.2", "@nuxt/fonts": "^0.10.3",
"@nuxt/image": "^1.8.1", "@nuxt/image": "^1.8.1",
"@nuxt/ui": "latest", "@nuxt/ui": "latest",
"@nuxt/ui-pro": "^1.5.0", "@nuxt/ui-pro": "^1.5.0",
"@nuxtjs/plausible": "^1.0.3", "@nuxtjs/plausible": "^1.2.0",
"@octokit/rest": "^21.0.2", "@octokit/rest": "^21.0.2",
"@vueuse/nuxt": "^11.2.0", "@vueuse/nuxt": "^12.0.0",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"joi": "^17.13.3", "joi": "^17.13.3",
"nuxt": "^3.14.159", "nuxt": "^3.14.1592",
"nuxt-cloudflare-analytics": "^1.0.8", "nuxt-cloudflare-analytics": "^1.0.8",
"nuxt-component-meta": "^0.9.0", "nuxt-component-meta": "^0.9.0",
"nuxt-og-image": "^3.0.8", "nuxt-og-image": "^3.1.1",
"prettier": "^3.3.3", "prettier": "^3.4.2",
"ufo": "^1.5.4", "ufo": "^1.5.4",
"v-calendar": "^3.1.2", "v-calendar": "^3.1.2",
"valibot": "^0.42.1", "valibot": "^0.42.1",
"yup": "^1.4.0", "yup": "^1.5.0",
"zod": "^3.23.8" "zod": "^3.23.8"
} }
} }

View File

@@ -1,8 +1,8 @@
{ {
"name": "@nuxt/ui", "name": "@nuxt/ui",
"description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.", "description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
"version": "2.19.2", "version": "2.20.0",
"packageManager": "pnpm@9.12.3", "packageManager": "pnpm@9.15.0",
"repository": "nuxt/ui", "repository": "nuxt/ui",
"homepage": "https://ui.nuxt.com", "homepage": "https://ui.nuxt.com",
"type": "module", "type": "module",
@@ -35,8 +35,8 @@
"@headlessui/tailwindcss": "^0.2.1", "@headlessui/tailwindcss": "^0.2.1",
"@headlessui/vue": "^1.7.23", "@headlessui/vue": "^1.7.23",
"@iconify-json/heroicons": "^1.2.1", "@iconify-json/heroicons": "^1.2.1",
"@nuxt/icon": "^1.7.2", "@nuxt/icon": "^1.9.1",
"@nuxt/kit": "^3.14.159", "@nuxt/kit": "^3.14.1592",
"@nuxtjs/color-mode": "^3.5.2", "@nuxtjs/color-mode": "^3.5.2",
"@nuxtjs/tailwindcss": "^6.12.2", "@nuxtjs/tailwindcss": "^6.12.2",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
@@ -44,44 +44,45 @@
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.9", "@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15", "@tailwindcss/typography": "^0.5.15",
"@vueuse/core": "^11.2.0", "@vueuse/core": "^12.0.0",
"@vueuse/integrations": "^11.2.0", "@vueuse/integrations": "^12.0.0",
"@vueuse/math": "^11.2.0", "@vueuse/math": "^12.0.0",
"defu": "^6.1.4", "defu": "^6.1.4",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"ohash": "^1.1.4", "ohash": "^1.1.4",
"pathe": "^1.1.2", "pathe": "^1.1.2",
"scule": "^1.3.0", "scule": "^1.3.0",
"tailwind-merge": "^2.5.4", "tailwind-merge": "^2.5.5",
"tailwindcss": "^3.4.14" "tailwindcss": "^3.4.16"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint-config": "^0.6.1", "@nuxt/eslint-config": "^0.7.2",
"@nuxt/module-builder": "^0.8.4", "@nuxt/module-builder": "^0.8.4",
"@nuxt/test-utils": "^3.14.4", "@nuxt/test-utils": "^3.15.1",
"@release-it/conventional-changelog": "^9.0.2", "@release-it/conventional-changelog": "^9.0.3",
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"eslint": "^9.14.0", "eslint": "^9.16.0",
"happy-dom": "^14.12.3", "happy-dom": "^14.12.3",
"joi": "^17.13.3", "joi": "^17.13.3",
"nuxt": "^3.14.159", "nuxt": "^3.14.1592",
"release-it": "^17.10.0", "release-it": "^17.10.0",
"superstruct": "^2.0.2", "superstruct": "^2.0.2",
"typescript": "^5.6.3",
"unbuild": "^2.0.0", "unbuild": "^2.0.0",
"valibot": "^0.42.1", "valibot": "^0.42.1",
"valibot30": "npm:valibot@0.30.0", "valibot30": "npm:valibot@0.30.0",
"valibot31": "npm:valibot@0.31.0", "valibot31": "npm:valibot@0.31.0",
"vitest": "^2.1.4", "vitest": "^2.1.8",
"vitest-environment-nuxt": "^1.0.1", "vitest-environment-nuxt": "^1.0.1",
"vue-tsc": "^2.1.10", "vue-tsc": "^2.1.10",
"yup": "^1.4.0", "yup": "^1.5.0",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"resolutions": { "resolutions": {
"@nuxt/ui": "workspace:*", "@nuxt/ui": "workspace:*",
"@nuxt/content": "2.13.2", "@nuxt/content": "2.13.2",
"@nuxtjs/mdc": "0.9.0", "@nuxtjs/mdc": "0.9.0",
"nuxt": "3.13.2", "chokidar": "3.6.0",
"@nuxt/kit": "3.13.2" "typescript": "5.6.3"
} }
} }

View File

@@ -9,6 +9,6 @@
}, },
"dependencies": { "dependencies": {
"@nuxt/ui": "latest", "@nuxt/ui": "latest",
"nuxt": "^3.14.159" "nuxt": "^3.14.1592"
} }
} }

4248
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -126,7 +126,7 @@ export default defineComponent({
default: () => ({}) default: () => ({})
} }
}, },
emits: ['open'], emits: ['open', 'close'],
setup(props, { emit }) { setup(props, { emit }) {
const { ui, attrs } = useUI('accordion', toRef(props, 'ui'), config, toRef(props, 'class')) const { ui, attrs } = useUI('accordion', toRef(props, 'ui'), config, toRef(props, 'class'))
@@ -142,6 +142,8 @@ export default defineComponent({
if (!isOpenBefore && isOpenAfter) { if (!isOpenBefore && isOpenAfter) {
emit('open', index) emit('open', index)
} else if (isOpenBefore && !isOpenAfter) {
emit('close', index)
} }
} }
}, { immediate: true }) }, { immediate: true })

View File

@@ -1,6 +1,18 @@
<template> <template>
<span :class="badgeClass" v-bind="attrs"> <span :class="badgeClass" v-bind="attrs">
<slot>{{ label }}</slot> <slot name="leading">
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="leadingIconClass" aria-hidden="true" />
</slot>
<slot>
<span v-if="label">
{{ label }}
</span>
</slot>
<slot name="trailing">
<UIcon v-if="isTrailing && trailingIconName" :name="trailingIconName" :class="trailingIconClass" aria-hidden="true" />
</slot>
</span> </span>
</template> </template>
@@ -8,6 +20,7 @@
import { computed, toRef, defineComponent } from 'vue' import { computed, toRef, defineComponent } from 'vue'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { twMerge, twJoin } from 'tailwind-merge' import { twMerge, twJoin } from 'tailwind-merge'
import UIcon from '../elements/Icon.vue'
import { useUI } from '../../composables/useUI' import { useUI } from '../../composables/useUI'
import { mergeConfig } from '../../utils' import { mergeConfig } from '../../utils'
import { useInjectButtonGroup } from '../../composables/useButtonGroup' import { useInjectButtonGroup } from '../../composables/useButtonGroup'
@@ -19,6 +32,9 @@ import { badge } from '#ui/ui.config'
const config = mergeConfig<typeof badge>(appConfig.ui.strategy, appConfig.ui.badge, badge) const config = mergeConfig<typeof badge>(appConfig.ui.strategy, appConfig.ui.badge, badge)
export default defineComponent({ export default defineComponent({
components: {
UIcon
},
inheritAttrs: false, inheritAttrs: false,
props: { props: {
size: { size: {
@@ -49,6 +65,26 @@ export default defineComponent({
type: [String, Number], type: [String, Number],
default: null default: null
}, },
icon: {
type: String,
default: null
},
leadingIcon: {
type: String,
default: null
},
trailingIcon: {
type: String,
default: null
},
trailing: {
type: Boolean,
default: false
},
leading: {
type: Boolean,
default: false
},
class: { class: {
type: [String, Object, Array] as PropType<any>, type: [String, Object, Array] as PropType<any>,
default: () => '' default: () => ''
@@ -63,6 +99,14 @@ export default defineComponent({
const { size, rounded } = useInjectButtonGroup({ ui, props }) const { size, rounded } = useInjectButtonGroup({ ui, props })
const isLeading = computed(() => {
return (props.icon && props.leading) || (props.icon && !props.trailing) || !props.trailing || props.leadingIcon
})
const isTrailing = computed(() => {
return (props.icon && props.trailing) || props.trailing || props.trailingIcon
})
const badgeClass = computed(() => { const badgeClass = computed(() => {
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant] const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
@@ -71,13 +115,42 @@ export default defineComponent({
ui.value.font, ui.value.font,
rounded.value, rounded.value,
ui.value.size[size.value], ui.value.size[size.value],
ui.value.gap[size.value],
variant?.replaceAll('{color}', props.color) variant?.replaceAll('{color}', props.color)
), props.class) ), props.class)
}) })
const leadingIconName = computed(() => {
return props.leadingIcon || props.icon
})
const trailingIconName = computed(() => {
return props.trailingIcon || props.icon
})
const leadingIconClass = computed(() => {
return twJoin(
ui.value.icon.base,
ui.value.icon.size[size.value]
)
})
const trailingIconClass = computed(() => {
return twJoin(
ui.value.icon.base,
ui.value.icon.size[size.value]
)
})
return { return {
attrs, attrs,
badgeClass isLeading,
isTrailing,
badgeClass,
leadingIconName,
trailingIconName,
leadingIconClass,
trailingIconClass
} }
} }
}) })

View File

@@ -106,7 +106,7 @@ export default defineComponent({
default: () => '' default: () => ''
}, },
ui: { ui: {
type: Object as PropType<DeepPartial<typeof config & { strategy?: Strategy }>>, type: Object as PropType<DeepPartial<typeof config> & { strategy?: Strategy }>,
default: undefined default: undefined
} }
}, },

View File

@@ -32,8 +32,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { isEqual } from 'ohash' import { isEqual, diff } from 'ohash'
import { defineComponent } from 'vue' import { type PropType, defineComponent } from 'vue'
import { nuxtLinkProps } from '../../utils' import { nuxtLinkProps } from '../../utils'
export default defineComponent({ export default defineComponent({
@@ -61,7 +61,7 @@ export default defineComponent({
default: false default: false
}, },
exactQuery: { exactQuery: {
type: Boolean, type: [Boolean, String] as PropType<boolean | 'partial'>,
default: false default: false
}, },
exactHash: { exactHash: {
@@ -74,9 +74,21 @@ export default defineComponent({
} }
}, },
setup(props) { setup(props) {
function isPartiallyEqual(item1, item2) {
const diffedKeys = diff(item1, item2).reduce((filtered, q) => {
if (q.type === 'added') {
filtered.push(q.key)
}
return filtered
}, [])
return isEqual(item1, item2, { excludeKeys: key => diffedKeys.includes(key) })
}
function resolveLinkClass(route, $route, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }) { function resolveLinkClass(route, $route, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }) {
if (props.exactQuery && !isEqual(route.query, $route.query)) { if (props.exactQuery === 'partial') {
return props.inactiveClass if (!isPartiallyEqual(route.query, $route.query)) return props.inactiveClass
} else if (props.exactQuery === true) {
if (!isEqual(route.query, $route.query)) return props.inactiveClass
} }
if (props.exactHash && route.hash !== $route.hash) { if (props.exactHash && route.hash !== $route.hash) {
return props.inactiveClass return props.inactiveClass

View File

@@ -60,6 +60,8 @@ export default defineComponent({
const formId = useId() const formId = useId()
const bus = useEventBus<FormEvent>(`form-${formId}`) const bus = useEventBus<FormEvent>(`form-${formId}`)
const parsedValue = ref(null)
onMounted(() => { onMounted(() => {
bus.on(async (event) => { bus.on(async (event) => {
if (event.type !== 'submit' && props.validateOn?.includes(event.type)) { if (event.type !== 'submit' && props.validateOn?.includes(event.type)) {
@@ -87,7 +89,7 @@ export default defineComponent({
if (errors) { if (errors) {
errs = errs.concat(errors) errs = errs.concat(errors)
} else { } else {
Object.assign(props.state, result) parsedValue.value = result
} }
} }
@@ -130,7 +132,7 @@ export default defineComponent({
if (props.validateOn?.includes('submit')) { if (props.validateOn?.includes('submit')) {
await validate() await validate()
} }
event.data = props.state event.data = props.schema ? parsedValue.value : props.state
emit('submit', event) emit('submit', event)
} catch (error) { } catch (error) {
if (!(error instanceof FormException)) { if (!(error instanceof FormException)) {
@@ -321,7 +323,7 @@ async function validateYupSchema(
schema: YupObjectSchema<any> schema: YupObjectSchema<any>
): Promise<ValidateReturnSchema<typeof state>> { ): Promise<ValidateReturnSchema<typeof state>> {
try { try {
const result = schema.validateSync(state, { abortEarly: false }) const result = await schema.validate(state, { abortEarly: false })
return { return {
errors: null, errors: null,
result result

View File

@@ -293,6 +293,24 @@ export default defineComponent({
const size = computed(() => sizeButtonGroup.value ?? sizeFormGroup.value) const size = computed(() => sizeButtonGroup.value ?? sizeFormGroup.value)
const by = computed(() => {
if (!props.by) return undefined
if (typeof props.by === 'function') {
return props.by
}
const key = props.by
const hasDot = key.indexOf('.')
if (hasDot > 0) {
return (a: any, z: any) => {
return accessor(a, key) === accessor(z, key)
}
}
return key
})
const internalQuery = ref('') const internalQuery = ref('')
const query = computed({ const query = computed({
get() { get() {
@@ -305,9 +323,7 @@ export default defineComponent({
}) })
const label = computed(() => { const label = computed(() => {
if (!props.modelValue) { if (!props.modelValue) return null
return
}
function getValue(value: any) { function getValue(value: any) {
if (props.valueAttribute) { if (props.valueAttribute) {
@@ -318,7 +334,7 @@ export default defineComponent({
} }
function compareValues(value1: any, value2: any) { function compareValues(value1: any, value2: any) {
if (props.by && typeof value1 === 'object' && typeof value2 === 'object') { if (by.value && typeof by.value !== 'function' && typeof value1 === 'object' && typeof value2 === 'object') {
return isEqual(value1[props.by], value2[props.by]) return isEqual(value1[props.by], value2[props.by])
} }
return isEqual(value1, value2) return isEqual(value1, value2)
@@ -507,7 +523,9 @@ export default defineComponent({
query, query,
accessor, accessor,
onUpdate, onUpdate,
onQueryChange onQueryChange,
// eslint-disable-next-line vue/no-dupe-keys
by
} }
} }
}) })

View File

@@ -348,6 +348,24 @@ export default defineComponent({
const [trigger, container] = usePopper(popper.value) const [trigger, container] = usePopper(popper.value)
const by = computed(() => {
if (!props.by) return undefined
if (typeof props.by === 'function') {
return props.by
}
const key = props.by
const hasDot = key.indexOf('.')
if (hasDot > 0) {
return (a: any, z: any) => {
return accessor(a, key) === accessor(z, key)
}
}
return key
})
const { size: sizeButtonGroup, rounded } = useInjectButtonGroup({ ui, props }) const { size: sizeButtonGroup, rounded } = useInjectButtonGroup({ ui, props })
const { emitFormBlur, emitFormChange, inputId, color, size: sizeFormGroup, name } = useFormGroup(props, config) const { emitFormBlur, emitFormChange, inputId, color, size: sizeFormGroup, name } = useFormGroup(props, config)
@@ -366,8 +384,8 @@ export default defineComponent({
const selected = computed(() => { const selected = computed(() => {
function compareValues(value1: any, value2: any) { function compareValues(value1: any, value2: any) {
if (props.by && typeof value1 === 'object' && typeof value2 === 'object') { if (by.value && typeof by.value !== 'function' && typeof value1 === 'object' && typeof value2 === 'object') {
return isEqual(value1[props.by], value2[props.by]) return isEqual(value1[by.value], value2[by.value])
} }
return isEqual(value1, value2) return isEqual(value1, value2)
} }
@@ -399,16 +417,12 @@ export default defineComponent({
}) })
const label = computed(() => { const label = computed(() => {
if (!selected.value) return null if (!props.modelValue) return null
if (props.valueAttribute) {
return accessor(selected.value as Record<string, any>, props.optionAttribute)
}
if (Array.isArray(props.modelValue) && props.modelValue.length) { if (Array.isArray(props.modelValue) && props.modelValue.length) {
return `${props.modelValue.length} selected` return `${props.modelValue.length} selected`
} else if (['string', 'number'].includes(typeof props.modelValue)) { } else if (['string', 'number'].includes(typeof props.modelValue)) {
return props.modelValue return props.valueAttribute ? accessor(selected.value, props.optionAttribute) : props.modelValue
} }
return accessor(props.modelValue as Record<string, any>, props.optionAttribute) return accessor(props.modelValue as Record<string, any>, props.optionAttribute)
@@ -612,7 +626,9 @@ export default defineComponent({
// eslint-disable-next-line vue/no-dupe-keys // eslint-disable-next-line vue/no-dupe-keys
query, query,
onUpdate, onUpdate,
onQueryChange onQueryChange,
// eslint-disable-next-line vue/no-dupe-keys
by
} }
} }
}) })

View File

@@ -117,6 +117,10 @@ export default defineComponent({
ui: { ui: {
type: Object as PropType<DeepPartial<typeof config> & { strategy?: Strategy }>, type: Object as PropType<DeepPartial<typeof config> & { strategy?: Strategy }>,
default: () => ({}) default: () => ({})
},
pauseTimeoutOnHover: {
type: Boolean,
default: true
} }
}, },
emits: ['close'], emits: ['close'],
@@ -157,13 +161,13 @@ export default defineComponent({
}) })
function onMouseover() { function onMouseover() {
if (timer) { if (props.pauseTimeoutOnHover && timer) {
timer.pause() timer.pause()
} }
} }
function onMouseleave() { function onMouseleave() {
if (timer) { if (props.pauseTimeoutOnHover && timer) {
timer.resume() timer.resume()
} }
} }

3
src/runtime/types/checkbox.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
import type colors from '#ui-colors'
export type CheckboxColor = typeof colors[number]

View File

@@ -1,3 +1,3 @@
import type { divider } from '#ui/ui.config' import type { divider } from '../ui.config'
export type DividerSize = keyof typeof divider.border.size.horizontal | keyof typeof divider.border.size.vertical export type DividerSize = keyof typeof divider.border.size.horizontal | keyof typeof divider.border.size.vertical

View File

@@ -4,6 +4,7 @@ export * from './avatar'
export * from './badge' export * from './badge'
export * from './breadcrumb' export * from './breadcrumb'
export * from './button' export * from './button'
export * from './checkbox'
export * from './chip' export * from './chip'
export * from './clipboard' export * from './clipboard'
export * from './command-palette' export * from './command-palette'

View File

@@ -6,7 +6,7 @@ export interface Link extends NuxtLinkProps {
disabled?: boolean disabled?: boolean
active?: boolean active?: boolean
exact?: boolean exact?: boolean
exactQuery?: boolean exactQuery?: boolean | 'partial'
exactHash?: boolean exactHash?: boolean
inactiveClass?: string inactiveClass?: string
} }

View File

@@ -7,7 +7,7 @@ export interface TightMap<O = any> {
export type DeepPartial<T, O = any> = { export type DeepPartial<T, O = any> = {
[P in keyof T]?: T[P] extends object [P in keyof T]?: T[P] extends object
? DeepPartial<T[P], O> ? DeepPartial<T[P], O>
: T[P]; : T[P] extends string ? string : T[P];
} & { } & {
[key: string]: O | TightMap<O> [key: string]: O | TightMap<O>
} }

View File

@@ -1,3 +1,5 @@
import type { ButtonColor, ButtonSize, ButtonVariant, CheckboxColor, ProgressAnimation, ProgressColor } from '../../types'
export default { export default {
wrapper: 'relative overflow-x-auto', wrapper: 'relative overflow-x-auto',
base: 'min-w-full table-fixed', base: 'min-w-full table-fixed',
@@ -51,23 +53,23 @@ export default {
icon: 'i-heroicons-arrows-up-down-20-solid', icon: 'i-heroicons-arrows-up-down-20-solid',
trailing: true, trailing: true,
square: true, square: true,
color: 'gray' as const, color: 'gray' as ButtonColor,
variant: 'ghost' as const, variant: 'ghost' as ButtonVariant,
class: '-m-1.5' class: '-m-1.5'
}, },
expandButton: { expandButton: {
icon: 'i-heroicons-chevron-down', icon: 'i-heroicons-chevron-down',
color: 'gray' as const, color: 'gray' as ButtonColor,
variant: 'ghost' as const, variant: 'ghost' as ButtonVariant,
size: 'xs' as const, size: 'xs' as ButtonSize,
class: '-my-1.5 align-middle' class: '-my-1.5 align-middle'
}, },
checkbox: { checkbox: {
color: 'primary' as const color: 'primary' as CheckboxColor
}, },
progress: { progress: {
color: 'primary' as const, color: 'primary' as ProgressColor,
animation: 'carousel' as const animation: 'carousel' as ProgressAnimation
}, },
loadingState: { loadingState: {
icon: 'i-heroicons-arrow-path-20-solid', icon: 'i-heroicons-arrow-path-20-solid',

View File

@@ -16,7 +16,7 @@ export default {
openIcon: 'i-heroicons-chevron-down-20-solid', openIcon: 'i-heroicons-chevron-down-20-solid',
closeIcon: '', closeIcon: '',
class: 'mb-1.5 w-full', class: 'mb-1.5 w-full',
variant: 'soft' as const, variant: 'soft',
truncate: true truncate: true
} }
} }

View File

@@ -1,3 +1,5 @@
import type { AvatarSize, ButtonColor, ButtonSize, ButtonVariant } from '../../types'
export default { export default {
wrapper: 'w-full relative overflow-hidden', wrapper: 'w-full relative overflow-hidden',
inner: 'w-0 flex-1', inner: 'w-0 flex-1',
@@ -13,7 +15,7 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0 self-center', base: 'flex-shrink-0 self-center',
size: 'md' as const size: 'md' as AvatarSize
}, },
color: { color: {
white: { white: {
@@ -32,9 +34,9 @@ export default {
icon: null, icon: null,
closeButton: null, closeButton: null,
actionButton: { actionButton: {
size: 'xs' as const, size: 'xs' as ButtonSize,
color: 'primary' as const, color: 'primary' as ButtonColor,
variant: 'link' as const variant: 'link' as ButtonVariant
} }
} }
} }

View File

@@ -8,6 +8,12 @@ export default {
md: 'text-sm px-2 py-1', md: 'text-sm px-2 py-1',
lg: 'text-sm px-2.5 py-1.5' lg: 'text-sm px-2.5 py-1.5'
}, },
gap: {
xs: 'gap-0.5',
sm: 'gap-1',
md: 'gap-1',
lg: 'gap-1.5'
},
color: { color: {
white: { white: {
solid: 'ring-1 ring-inset ring-gray-300 dark:ring-gray-700 text-gray-900 dark:text-white bg-white dark:bg-gray-900' solid: 'ring-1 ring-inset ring-gray-300 dark:ring-gray-700 text-gray-900 dark:text-white bg-white dark:bg-gray-900'
@@ -25,6 +31,15 @@ export default {
soft: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400', soft: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400',
subtle: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400 ring-1 ring-inset ring-{color}-500 dark:ring-{color}-400 ring-opacity-25 dark:ring-opacity-25' subtle: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400 ring-1 ring-inset ring-{color}-500 dark:ring-{color}-400 ring-opacity-25 dark:ring-opacity-25'
}, },
icon: {
base: 'flex-shrink-0',
size: {
xs: 'h-4 w-4',
sm: 'h-4 w-4',
md: 'h-5 w-5',
lg: 'h-5 w-5'
}
},
default: { default: {
size: 'sm', size: 'sm',
variant: 'solid', variant: 'solid',

View File

@@ -1,3 +1,5 @@
import type { ButtonColor } from '../../types'
export default { export default {
wrapper: 'relative', wrapper: 'relative',
container: 'relative w-full flex overflow-x-auto snap-x snap-mandatory scroll-smooth', container: 'relative w-full flex overflow-x-auto snap-x snap-mandatory scroll-smooth',
@@ -13,12 +15,12 @@ export default {
}, },
default: { default: {
prevButton: { prevButton: {
color: 'black' as const, color: 'black' as ButtonColor,
class: 'rtl:[&_span:first-child]:rotate-180 absolute start-4 top-1/2 transform -translate-y-1/2 rounded-full', class: 'rtl:[&_span:first-child]:rotate-180 absolute start-4 top-1/2 transform -translate-y-1/2 rounded-full',
icon: 'i-heroicons-chevron-left-20-solid' icon: 'i-heroicons-chevron-left-20-solid'
}, },
nextButton: { nextButton: {
color: 'black' as const, color: 'black' as ButtonColor,
class: 'rtl:[&_span:last-child]:rotate-180 absolute end-4 top-1/2 transform -translate-y-1/2 rounded-full', class: 'rtl:[&_span:last-child]:rotate-180 absolute end-4 top-1/2 transform -translate-y-1/2 rounded-full',
icon: 'i-heroicons-chevron-right-20-solid' icon: 'i-heroicons-chevron-right-20-solid'
} }

View File

@@ -1,3 +1,4 @@
import type { AvatarSize } from '../../types'
import { arrow } from '../popper' import { arrow } from '../popper'
export default { export default {
@@ -28,7 +29,7 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
label: 'truncate', label: 'truncate',
shortcuts: 'hidden md:inline-flex flex-shrink-0 gap-0.5 ms-auto' shortcuts: 'hidden md:inline-flex flex-shrink-0 gap-0.5 ms-auto'

View File

@@ -1,3 +1,4 @@
import type { AvatarSize } from '../../types'
import { arrow } from '../popper' import { arrow } from '../popper'
export default { export default {
@@ -36,7 +37,7 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
chip: { chip: {
base: 'flex-shrink-0 w-2 h-2 mx-1 rounded-full' base: 'flex-shrink-0 w-2 h-2 mx-1 rounded-full'

View File

@@ -1,3 +1,5 @@
import type { AvatarSize } from '../../types'
export default { export default {
wrapper: { wrapper: {
base: 'flex items-center align-center text-center', base: 'flex items-center align-center text-center',
@@ -42,11 +44,11 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
label: 'text-sm', label: 'text-sm',
default: { default: {
size: '2xs' as const, size: '2xs',
type: 'solid' as const type: 'solid'
} }
} }

View File

@@ -1,3 +1,5 @@
import type { AvatarSize } from '../../types'
export default { export default {
wrapper: 'flex flex-col flex-1 min-h-0 divide-y divide-gray-100 dark:divide-gray-800', wrapper: 'flex flex-col flex-1 min-h-0 divide-y divide-gray-100 dark:divide-gray-800',
container: 'relative flex-1 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-800 scroll-py-2', container: 'relative flex-1 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-800 scroll-py-2',
@@ -46,7 +48,7 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
chip: { chip: {
base: 'flex-shrink-0 w-2 h-2 mx-1 rounded-full' base: 'flex-shrink-0 w-2 h-2 mx-1 rounded-full'

View File

@@ -1,3 +1,5 @@
import type { AvatarSize, BadgeColor, BadgeSize, BadgeVariant } from '../../types'
export default { export default {
wrapper: 'relative w-full flex items-center justify-between', wrapper: 'relative w-full flex items-center justify-between',
container: 'flex items-center min-w-0', container: 'flex items-center min-w-0',
@@ -15,12 +17,12 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
badge: { badge: {
base: 'flex-shrink-0 ms-auto relative rounded', base: 'flex-shrink-0 ms-auto relative rounded',
color: 'gray' as const, color: 'gray' as BadgeColor,
variant: 'solid' as const, variant: 'solid' as BadgeVariant,
size: 'xs' as const size: 'xs' as BadgeSize
} }
} }

View File

@@ -1,3 +1,5 @@
import type { ButtonColor } from '../../types'
export default { export default {
wrapper: 'flex items-center -space-x-px', wrapper: 'flex items-center -space-x-px',
base: '', base: '',
@@ -5,28 +7,28 @@ export default {
default: { default: {
size: 'sm', size: 'sm',
activeButton: { activeButton: {
color: 'primary' as const color: 'primary' as ButtonColor
}, },
inactiveButton: { inactiveButton: {
color: 'white' as const color: 'white' as ButtonColor
}, },
firstButton: { firstButton: {
color: 'white' as const, color: 'white' as ButtonColor,
class: 'rtl:[&_span:first-child]:rotate-180', class: 'rtl:[&_span:first-child]:rotate-180',
icon: 'i-heroicons-chevron-double-left-20-solid' icon: 'i-heroicons-chevron-double-left-20-solid'
}, },
lastButton: { lastButton: {
color: 'white' as const, color: 'white' as ButtonColor,
class: 'rtl:[&_span:last-child]:rotate-180', class: 'rtl:[&_span:last-child]:rotate-180',
icon: 'i-heroicons-chevron-double-right-20-solid' icon: 'i-heroicons-chevron-double-right-20-solid'
}, },
prevButton: { prevButton: {
color: 'white' as const, color: 'white' as ButtonColor,
class: 'rtl:[&_span:first-child]:rotate-180', class: 'rtl:[&_span:first-child]:rotate-180',
icon: 'i-heroicons-chevron-left-20-solid' icon: 'i-heroicons-chevron-left-20-solid'
}, },
nextButton: { nextButton: {
color: 'white' as const, color: 'white' as ButtonColor,
class: 'rtl:[&_span:last-child]:rotate-180', class: 'rtl:[&_span:last-child]:rotate-180',
icon: 'i-heroicons-chevron-right-20-solid' icon: 'i-heroicons-chevron-right-20-solid'
} }

View File

@@ -1,3 +1,5 @@
import type { AvatarSize, BadgeColor, BadgeSize, BadgeVariant } from '../../types'
export default { export default {
wrapper: 'relative', wrapper: 'relative',
base: 'group relative flex items-center gap-1.5 focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-1 focus-visible:before:ring-primary-500 dark:focus-visible:before:ring-primary-400 before:absolute before:inset-px before:rounded-md disabled:cursor-not-allowed disabled:opacity-75', base: 'group relative flex items-center gap-1.5 focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-1 focus-visible:before:ring-primary-500 dark:focus-visible:before:ring-primary-400 before:absolute before:inset-px before:rounded-md disabled:cursor-not-allowed disabled:opacity-75',
@@ -17,13 +19,13 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0', base: 'flex-shrink-0',
size: '2xs' as const size: '2xs' as AvatarSize
}, },
badge: { badge: {
base: 'flex-shrink-0 ms-auto relative rounded', base: 'flex-shrink-0 ms-auto relative rounded',
color: 'gray' as const, color: 'gray' as BadgeColor,
variant: 'solid' as const, variant: 'solid' as BadgeVariant,
size: 'xs' as const size: 'xs' as BadgeSize
}, },
divider: { divider: {
wrapper: { wrapper: {

View File

@@ -1,3 +1,5 @@
import type { AvatarSize, ButtonColor, ButtonSize, ButtonVariant } from '../../types'
export default { export default {
wrapper: 'w-full pointer-events-auto', wrapper: 'w-full pointer-events-auto',
container: 'relative overflow-hidden', container: 'relative overflow-hidden',
@@ -17,7 +19,7 @@ export default {
}, },
avatar: { avatar: {
base: 'flex-shrink-0 self-center', base: 'flex-shrink-0 self-center',
size: 'md' as const size: 'md' as AvatarSize
}, },
progress: { progress: {
base: 'absolute bottom-0 end-0 start-0 h-1', base: 'absolute bottom-0 end-0 start-0 h-1',
@@ -38,13 +40,13 @@ export default {
timeout: 5000, timeout: 5000,
closeButton: { closeButton: {
icon: 'i-heroicons-x-mark-20-solid', icon: 'i-heroicons-x-mark-20-solid',
color: 'gray' as const, color: 'gray' as ButtonColor,
variant: 'link' as const, variant: 'link' as ButtonVariant,
padded: false padded: false
}, },
actionButton: { actionButton: {
size: 'xs' as const, size: 'xs' as ButtonSize,
color: 'white' as const color: 'white' as ButtonColor
} }
} }
} }