mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 12:39:35 +01:00
Compare commits
77 Commits
chore/dyna
...
fix/3952
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
266e870e67 | ||
|
|
d140acc608 | ||
|
|
cc20a26f07 | ||
|
|
983c6382d1 | ||
|
|
37eabc89bd | ||
|
|
a57844e416 | ||
|
|
2be60cddfe | ||
|
|
09b4699aea | ||
|
|
46c2987ebf | ||
|
|
f244d15b96 | ||
|
|
aaa60c0798 | ||
|
|
5467d71cc2 | ||
|
|
941a54e5e3 | ||
|
|
655f98ffed | ||
|
|
999a0f8467 | ||
|
|
2739939c46 | ||
|
|
2a241c87c3 | ||
|
|
e6e510b848 | ||
|
|
a655da1394 | ||
|
|
3a71256d59 | ||
|
|
404359a6ca | ||
|
|
1e4e9c4708 | ||
|
|
6f07f6bd6e | ||
|
|
4c1093bde4 | ||
|
|
322a6f467a | ||
|
|
7d51a9e479 | ||
|
|
04bdbcfc6e | ||
|
|
58aa296425 | ||
|
|
d3df3bb929 | ||
|
|
4863775e17 | ||
|
|
7551a85ad2 | ||
|
|
c2bcb8e264 | ||
|
|
0c1417b6b1 | ||
|
|
88124b85c5 | ||
|
|
9f539c9545 | ||
|
|
41d4ffe5b5 | ||
|
|
d8a0bbe710 | ||
|
|
06e5689da8 | ||
|
|
67d19f582a | ||
|
|
650bc40253 | ||
|
|
2f0f317a12 | ||
|
|
d2a26939ad | ||
|
|
b7a8146898 | ||
|
|
e81464a43e | ||
|
|
4b3d2a7b00 | ||
|
|
6f6fa6ae4a | ||
|
|
c7bb6d4c4b | ||
|
|
c23f85fe33 | ||
|
|
591d59fe89 | ||
|
|
caa3bf9c7e | ||
|
|
2731011bb7 | ||
|
|
aebf0b3dca | ||
|
|
6651987dc6 | ||
|
|
7c4329ded7 | ||
|
|
61aabd72e4 | ||
|
|
8dfdd63ce3 | ||
|
|
e6369a6746 | ||
|
|
a4f3f6d531 | ||
|
|
c5bdec0f64 | ||
|
|
adf11f4326 | ||
|
|
b507f69b87 | ||
|
|
67bcb496a9 | ||
|
|
4104cd993b | ||
|
|
e8d493a00e | ||
|
|
0f2d2e5d03 | ||
|
|
4d17989302 | ||
|
|
eb7607749d | ||
|
|
c0347f6e06 | ||
|
|
6366118709 | ||
|
|
9f7f5910ee | ||
|
|
996573f26d | ||
|
|
88ff542e63 | ||
|
|
1a119e6279 | ||
|
|
776aef6e7f | ||
|
|
8284d05529 | ||
|
|
713e943144 | ||
|
|
505c1e502a |
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
@@ -44,7 +44,7 @@ body:
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction
|
||||
description: Please provide a reproduction link using the Nuxt template https://codesandbox.io/p/devbox/nuxt-ui3-n3sxks or the Vue template https://codesandbox.io/p/devbox/nuxt-ui3-vue-4h5gqn. A minimal [reproduction is required](https://antfu.me/posts/why-reproductions-are-required) unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided we might close it.
|
||||
description: Please provide a reproduction link using the Nuxt template https://codesandbox.io/p/devbox/nuxt-ui3-n3sxks or the Vue template https://codesandbox.io/p/devbox/nuxt-ui3-vue-4h5gqn. A minimal [reproduction is required](https://antfu.me/posts/why-reproductions-are-required) unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided, it will be closed automatically after a while.
|
||||
placeholder: https://github.com/my/reproduction
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
30
.github/reproduire/needs-reproduction.md
vendored
Normal file
30
.github/reproduire/needs-reproduction.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
Would you be able to provide a [reproduction](https://nuxt.com/docs/community/reporting-bugs/#create-a-minimal-reproduction)? 🙏
|
||||
|
||||
<details>
|
||||
<summary>More info</summary>
|
||||
|
||||
### Why do I need to provide a reproduction?
|
||||
|
||||
Reproductions make it possible for us to triage and fix issues quickly with a relatively small team. It helps us discover the source of the problem, and also can reveal assumptions you or we might be making.
|
||||
|
||||
### What will happen?
|
||||
|
||||
If you've provided a reproduction, we'll remove the label and try to reproduce the issue. If we can, we'll mark it as a bug and prioritise it based on its severity and how many people we think it might affect.
|
||||
|
||||
If `needs reproduction` labeled issues don't receive any substantial activity (e.g., new comments featuring a reproduction link), they will be closed automatically after a while. That's not because we don't care! At any point, feel free to comment with a reproduction and we'll reopen it.
|
||||
|
||||
### How can I create a reproduction?
|
||||
|
||||
We have templates to create a minimal reproduction:
|
||||
|
||||
* **Nuxt**: https://codesandbox.io/p/devbox/nuxt-ui3-n3sxks
|
||||
* **Vue**: https://codesandbox.io/p/devbox/nuxt-ui3-vue-4h5gqn
|
||||
|
||||
Please ensure that the reproduction is as **minimal** as possible. See more details [in our guide](https://nuxt.com/docs/community/reporting-bugs/#create-a-minimal-reproduction).
|
||||
|
||||
You might also find these other articles interesting and/or helpful:
|
||||
|
||||
- [The Importance of Reproductions](https://antfu.me/posts/why-reproductions-are-required)
|
||||
- [How to Generate a Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/mcve)
|
||||
|
||||
</details>
|
||||
17
.github/workflows/reproduire.yml
vendored
Normal file
17
.github/workflows/reproduire.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: reproduire
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
reproduire:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: Hebilicious/reproduire@4b686ae9cbb72dad60f001d278b6e3b2ce40a9ac # v0.0.9-mp
|
||||
with:
|
||||
label: needs reproduction
|
||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
## [3.1.1](https://github.com/nuxt/ui/compare/v3.1.0...v3.1.1) (2025-05-02)
|
||||
|
||||
### Features
|
||||
|
||||
* **useOverlay:** add `closeAll` method ([#3984](https://github.com/nuxt/ui/issues/3984)) ([ac4c194](https://github.com/nuxt/ui/commit/ac4c1946ec399aec59b4bce9d538e3ff67868abf))
|
||||
* **useOverlay:** add `isOpen` method to check overlay state ([#4041](https://github.com/nuxt/ui/issues/4041)) ([a4f3f6d](https://github.com/nuxt/ui/commit/a4f3f6d531f9c0281f99085a6688d296f8f13f2f))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Calendar:** add `place-items-center` to grid row ([#4034](https://github.com/nuxt/ui/issues/4034)) ([8dfdd63](https://github.com/nuxt/ui/commit/8dfdd63ce3b3a0e904f7c013c774cf9aaf46b240))
|
||||
* **defineShortcuts:** bring back `meta` to `ctrl` convert on non macos platforms ([f3b8b17](https://github.com/nuxt/ui/commit/f3b8b17dc5f43936ef7ffb11c1ed7f9a5f94d0bb)), closes [#3869](https://github.com/nuxt/ui/issues/3869) [#3318](https://github.com/nuxt/ui/issues/3318)
|
||||
* **module:** support `nuxt-nightly` ([#3996](https://github.com/nuxt/ui/issues/3996)) ([bc0a296](https://github.com/nuxt/ui/commit/bc0a296f9d68ca72cd991b11cd3489b63c7b13db))
|
||||
* **NavigationMenu:** remove `sm:w-auto` from content slot ([aebf0b3](https://github.com/nuxt/ui/commit/aebf0b3dca50c51c093cb6abf16c4fd995fc1b39)), closes [#3987](https://github.com/nuxt/ui/issues/3987)
|
||||
* **RadioGroup:** improve items `value` field type ([#3995](https://github.com/nuxt/ui/issues/3995)) ([195773e](https://github.com/nuxt/ui/commit/195773ec7dac12ccc3a0a67867751e8ca634cc04))
|
||||
* **templates:** put back args to watch in dev ([#4033](https://github.com/nuxt/ui/issues/4033)) ([c5bdec0](https://github.com/nuxt/ui/commit/c5bdec0f64963ef602975270a09a1ee795cdacf9))
|
||||
* **theme:** add missing `border-bg` / `divide-bg` utilities ([82b5f32](https://github.com/nuxt/ui/commit/82b5f322ebd8a08e63588122bd4ef567dcb8ba8c))
|
||||
* **theme:** add missing `ring-offset-*` utilities ([#3992](https://github.com/nuxt/ui/issues/3992)) ([e5df026](https://github.com/nuxt/ui/commit/e5df0269935be59df759fe0e1378acb2b0d9014a))
|
||||
* **theme:** define default shades for named tailwindcss colors ([8acf3c5](https://github.com/nuxt/ui/commit/8acf3c51db6c2f9443d04be6ba7d9f062c5cf8ab)), closes [#3977](https://github.com/nuxt/ui/issues/3977)
|
||||
* **theme:** improve app config types for `ui` object ([591d59f](https://github.com/nuxt/ui/commit/591d59fe89f1d9bf016c121bf9160f73fe0a290d)), closes [#3579](https://github.com/nuxt/ui/issues/3579)
|
||||
* **theme:** use `[@theme](https://github.com/theme) inline` to properly reference css variables ([6131871](https://github.com/nuxt/ui/commit/6131871a0d124c5942d60dc5dff20981e8542e51)), closes [#4018](https://github.com/nuxt/ui/issues/4018)
|
||||
* **useOverlay:** improve types and docs ([#4012](https://github.com/nuxt/ui/issues/4012)) ([39e29fc](https://github.com/nuxt/ui/commit/39e29fccf1840c723a13237d65002501b2829b70))
|
||||
|
||||
## [3.1.0](https://github.com/nuxt/ui/compare/v3.0.2...v3.1.0) (2025-04-24)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
@@ -11,7 +11,7 @@ export default defineBuildConfig({
|
||||
delimiters: ['', ''],
|
||||
values: {
|
||||
// Used in development to import directly from theme
|
||||
'const isUiDev = true': 'const isUiDev = false'
|
||||
'process.argv.includes(\'--uiDev\')': 'false'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -66,7 +66,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<slot />
|
||||
</Primitive>
|
||||
</template>
|
||||
@@ -109,7 +109,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<${upperName}Root v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })" />
|
||||
<${upperName}Root v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })" />
|
||||
</template>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ watch(framework, () => {
|
||||
color="neutral"
|
||||
:ui="{
|
||||
indicator: 'bg-default',
|
||||
trigger: 'px-1 data-[state=active]:text-highlighted'
|
||||
trigger: 'px-1 data-[state=active]:text-highlighted w-full'
|
||||
}"
|
||||
size="xs"
|
||||
@update:model-value="(framework = $event as string)"
|
||||
|
||||
@@ -20,7 +20,7 @@ watch(module, () => {
|
||||
color="neutral"
|
||||
:ui="{
|
||||
indicator: 'bg-default',
|
||||
trigger: 'px-1 data-[state=active]:text-highlighted'
|
||||
trigger: 'px-1 data-[state=active]:text-highlighted w-full'
|
||||
}"
|
||||
size="xs"
|
||||
@update:model-value="(module = $event as string)"
|
||||
|
||||
@@ -17,9 +17,12 @@ function onClickPrev() {
|
||||
function onClickNext() {
|
||||
activeIndex.value++
|
||||
}
|
||||
|
||||
function onSelect(index: number) {
|
||||
activeIndex.value = index
|
||||
}
|
||||
|
||||
function select(index: number) {
|
||||
activeIndex.value = index
|
||||
|
||||
carousel.value?.emblaApi?.scrollTo(index)
|
||||
}
|
||||
@@ -35,6 +38,7 @@ function onSelect(index: number) {
|
||||
:prev="{ onClick: onClickPrev }"
|
||||
:next="{ onClick: onClickNext }"
|
||||
class="w-full max-w-xs mx-auto"
|
||||
@select="onSelect"
|
||||
>
|
||||
<img :src="item" width="320" height="320" class="rounded-lg">
|
||||
</UCarousel>
|
||||
@@ -45,7 +49,7 @@ function onSelect(index: number) {
|
||||
:key="index"
|
||||
class="size-11 opacity-25 hover:opacity-100 transition-opacity"
|
||||
:class="{ 'opacity-100': activeIndex === index }"
|
||||
@click="onSelect(index)"
|
||||
@click="select(index)"
|
||||
>
|
||||
<img :src="item" width="44" height="44" class="rounded-lg">
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'command-palette-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
|
||||
@@ -13,7 +13,9 @@ const modal = overlay.create(LazyModalExample, {
|
||||
})
|
||||
|
||||
async function open() {
|
||||
const shouldIncrement = await modal.open()
|
||||
const instance = modal.open()
|
||||
|
||||
const shouldIncrement = await instance.result
|
||||
|
||||
if (shouldIncrement) {
|
||||
count.value++
|
||||
|
||||
@@ -65,6 +65,7 @@ const items = [
|
||||
class="w-full justify-center"
|
||||
:ui="{
|
||||
viewport: 'sm:w-(--reka-navigation-menu-viewport-width)',
|
||||
content: 'sm:w-auto',
|
||||
childList: 'sm:w-96',
|
||||
childLinkDescription: 'text-balance line-clamp-2'
|
||||
}"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
params: { q: searchTermDebounced },
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
return data?.map(user => ({
|
||||
|
||||
@@ -13,7 +13,9 @@ const slideover = overlay.create(LazySlideoverExample, {
|
||||
})
|
||||
|
||||
async function open() {
|
||||
const shouldIncrement = await slideover.open()
|
||||
const instance = slideover.open()
|
||||
|
||||
const shouldIncrement = await instance.result
|
||||
|
||||
if (shouldIncrement) {
|
||||
count.value++
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
<script setup lang="ts">
|
||||
import { h, resolveComponent } from 'vue'
|
||||
import type { TableColumn } from '@nuxt/ui'
|
||||
import { getGroupedRowModel, type GroupingOptions } from '@tanstack/vue-table'
|
||||
|
||||
const UBadge = resolveComponent('UBadge')
|
||||
|
||||
type Account = {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
type PaymentStatus = 'paid' | 'failed' | 'refunded'
|
||||
|
||||
type Payment = {
|
||||
id: string
|
||||
date: string
|
||||
status: PaymentStatus
|
||||
email: string
|
||||
amount: number
|
||||
account: Account
|
||||
}
|
||||
|
||||
const getColorByStatus = (status: PaymentStatus) => {
|
||||
return {
|
||||
paid: 'success',
|
||||
failed: 'error',
|
||||
refunded: 'neutral'
|
||||
}[status]
|
||||
}
|
||||
|
||||
const data = ref<Payment[]>([
|
||||
{
|
||||
id: '4600',
|
||||
date: '2024-03-11T15:30:00',
|
||||
status: 'paid',
|
||||
email: 'james.anderson@example.com',
|
||||
amount: 594,
|
||||
account: {
|
||||
id: '1',
|
||||
name: 'Account 1'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '4599',
|
||||
date: '2024-03-11T10:10:00',
|
||||
status: 'failed',
|
||||
email: 'mia.white@example.com',
|
||||
amount: 276,
|
||||
account: {
|
||||
id: '2',
|
||||
name: 'Account 2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '4598',
|
||||
date: '2024-03-11T08:50:00',
|
||||
status: 'refunded',
|
||||
email: 'william.brown@example.com',
|
||||
amount: 315,
|
||||
account: {
|
||||
id: '1',
|
||||
name: 'Account 1'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '4597',
|
||||
date: '2024-03-10T19:45:00',
|
||||
status: 'paid',
|
||||
email: 'emma.davis@example.com',
|
||||
amount: 529,
|
||||
account: {
|
||||
id: '2',
|
||||
name: 'Account 2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '4596',
|
||||
date: '2024-03-10T15:55:00',
|
||||
status: 'paid',
|
||||
email: 'ethan.harris@example.com',
|
||||
amount: 639,
|
||||
account: {
|
||||
id: '1',
|
||||
name: 'Account 1'
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const columns: TableColumn<Payment>[] = [
|
||||
{
|
||||
id: 'title',
|
||||
header: 'Item'
|
||||
},
|
||||
{
|
||||
id: 'account_id',
|
||||
accessorKey: 'account.id'
|
||||
},
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: '#',
|
||||
cell: ({ row }) =>
|
||||
row.getIsGrouped()
|
||||
? `${row.getValue('id')} records`
|
||||
: `#${row.getValue('id')}`,
|
||||
aggregationFn: 'count'
|
||||
},
|
||||
{
|
||||
accessorKey: 'date',
|
||||
header: 'Date',
|
||||
cell: ({ row }) => {
|
||||
return new Date(row.getValue('date')).toLocaleString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
})
|
||||
},
|
||||
aggregationFn: 'max'
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: 'Status'
|
||||
},
|
||||
{
|
||||
accessorKey: 'email',
|
||||
header: 'Email',
|
||||
meta: {
|
||||
class: {
|
||||
td: 'w-full'
|
||||
}
|
||||
},
|
||||
cell: ({ row }) =>
|
||||
row.getIsGrouped()
|
||||
? `${row.getValue('email')} customers`
|
||||
: row.getValue('email'),
|
||||
aggregationFn: 'uniqueCount'
|
||||
},
|
||||
{
|
||||
accessorKey: 'amount',
|
||||
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||
cell: ({ row }) => {
|
||||
const amount = Number.parseFloat(row.getValue('amount'))
|
||||
|
||||
const formatted = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'EUR'
|
||||
}).format(amount)
|
||||
|
||||
return h('div', { class: 'text-right font-medium' }, formatted)
|
||||
},
|
||||
aggregationFn: 'sum'
|
||||
}
|
||||
]
|
||||
|
||||
const grouping_options = ref<GroupingOptions>({
|
||||
groupedColumnMode: 'remove',
|
||||
getGroupedRowModel: getGroupedRowModel()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:grouping="['account_id', 'status']"
|
||||
:grouping-options="grouping_options"
|
||||
:ui="{
|
||||
root: 'min-w-full',
|
||||
td: 'empty:p-0' // helps with the colspaned row added for expand slot
|
||||
}"
|
||||
>
|
||||
<template #title-cell="{ row }">
|
||||
<div v-if="row.getIsGrouped()" class="flex items-center">
|
||||
<span
|
||||
class="inline-block"
|
||||
:style="{ width: `calc(${row.depth} * 1rem)` }"
|
||||
/>
|
||||
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="neutral"
|
||||
class="mr-2"
|
||||
size="xs"
|
||||
:icon="row.getIsExpanded() ? 'i-lucide-minus' : 'i-lucide-plus'"
|
||||
@click="row.toggleExpanded()"
|
||||
/>
|
||||
<strong v-if="row.groupingColumnId === 'account_id'">{{
|
||||
row.original.account.name
|
||||
}}</strong>
|
||||
<UBadge
|
||||
v-else-if="row.groupingColumnId === 'status'"
|
||||
:color="getColorByStatus(row.original.status)"
|
||||
class="capitalize"
|
||||
variant="subtle"
|
||||
>
|
||||
{{ row.original.status }}
|
||||
</UBadge>
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
@@ -26,7 +26,7 @@ const state = reactive({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTabs :items="items" variant="link" class="gap-4 w-full" :ui="{ trigger: 'flex-1' }">
|
||||
<UTabs :items="items" variant="link" class="gap-4 w-full" :ui="{ trigger: 'grow' }">
|
||||
<template #account="{ item }">
|
||||
<p class="text-muted mb-4">
|
||||
{{ item.description }}
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const items: TabsItem[] = [
|
||||
{
|
||||
label: 'Account'
|
||||
label: 'Account',
|
||||
value: 'account'
|
||||
},
|
||||
{
|
||||
label: 'Password'
|
||||
label: 'Password',
|
||||
value: 'password'
|
||||
}
|
||||
]
|
||||
|
||||
const active = ref('0')
|
||||
|
||||
// Note: This is for demonstration purposes only. Don't do this at home.
|
||||
onMounted(() => {
|
||||
setInterval(() => {
|
||||
active.value = String((Number(active.value) + 1) % items.length)
|
||||
}, 2000)
|
||||
const active = computed({
|
||||
get() {
|
||||
return (route.query.tab as string) || 'account'
|
||||
},
|
||||
set(tab) {
|
||||
// Hash is specified here to prevent the page from scrolling to the top
|
||||
router.push({
|
||||
path: '/components/tabs',
|
||||
query: { tab },
|
||||
hash: '#control-active-item'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export function useLinks() {
|
||||
label: 'Raycast Extension',
|
||||
description: 'Access Nuxt UI components without leaving your editor.',
|
||||
icon: 'i-simple-icons-raycast',
|
||||
to: 'https://www.raycast.com/HugoRCD/nuxt-ui',
|
||||
to: 'https://www.raycast.com/HugoRCD/nuxt',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Figma to Code',
|
||||
|
||||
@@ -239,7 +239,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
||||
<li>
|
||||
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
|
||||
<p class="text-4xl font-semibold text-highlighted truncate">
|
||||
175+
|
||||
200+
|
||||
</p>
|
||||
<p class="text-muted text-sm truncate">Contributors</p>
|
||||
</NuxtLink>
|
||||
|
||||
@@ -55,6 +55,7 @@ const icons = {
|
||||
:title="user.name"
|
||||
:description="[user.pronouns, user.location].filter(Boolean).join(' ・ ')"
|
||||
:ui="{
|
||||
wrapper: 'items-center',
|
||||
container: 'gap-y-4 lg:p-8',
|
||||
leading: 'flex justify-center',
|
||||
title: 'text-center',
|
||||
@@ -123,6 +124,7 @@ const icons = {
|
||||
:key="contributor.username"
|
||||
:title="contributor.username"
|
||||
:ui="{
|
||||
wrapper: 'items-center',
|
||||
container: 'gap-y-2',
|
||||
leading: 'flex justify-center',
|
||||
title: 'text-center',
|
||||
|
||||
@@ -973,7 +973,7 @@ export default {
|
||||
|
||||
```vue [src/runtime/components/Card.vue]
|
||||
<template>
|
||||
<div :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<div :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ Here's an overview of the key directories and files in the Nuxt UI project struc
|
||||
|
||||
### Documentation
|
||||
|
||||
The documentation lives in the `docs` folder as a Nuxt app using `@nuxt/content` v3 to generate pages from Markdown files. See the [Content v3 Docs](https://content3.nuxt.dev/docs/getting-started) for details on how it works. Here's a breakdown of its structure:
|
||||
The documentation lives in the `docs` folder as a Nuxt app using `@nuxt/content` v3 to generate pages from Markdown files. See the [Nuxt Content documentation](https://content.nuxt.com/docs/getting-started) for details on how it works. Here's a breakdown of its structure:
|
||||
|
||||
```bash
|
||||
├── app/
|
||||
|
||||
@@ -62,10 +62,17 @@ Update an overlay using its `id`
|
||||
- `id`: The identifier of the overlay
|
||||
- `props`: An object of props to update on the rendered component.
|
||||
|
||||
### `unmount(id: symbol): void`
|
||||
### `unMount(id: symbol): void`
|
||||
|
||||
Removes the overlay from the DOM using its `id`
|
||||
|
||||
- Parameters:
|
||||
- `id`: The identifier of the overlay
|
||||
|
||||
### `isOpen(id: symbol): boolean`
|
||||
|
||||
Checks if an overlay its open using its `id`
|
||||
|
||||
- Parameters:
|
||||
- `id`: The identifier of the overlay
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ It requires two props:
|
||||
**No validation library is included** by default, ensure you **install the one you need**.
|
||||
::
|
||||
|
||||
::tabs
|
||||
::tabs{class="gap-0"}
|
||||
::component-example{label="Valibot"}
|
||||
---
|
||||
name: 'form-example-valibot'
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
---
|
||||
title: Keyboard Key
|
||||
title: Kbd
|
||||
description: A kbd element to display a keyboard key.
|
||||
category: element
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Kbd.vue
|
||||
navigation:
|
||||
title: Kbd
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -21,8 +21,12 @@ Use the `items` prop as an array of objects with the following properties:
|
||||
- `icon?: string`{lang="ts-type"}
|
||||
- `avatar?: AvatarProps`{lang="ts-type"}
|
||||
- `badge?: string | number | BadgeProps`{lang="ts-type"}
|
||||
- `tooltip?: TooltipProps`{lang="ts-type"}
|
||||
- `trailingIcon?: string`{lang="ts-type"}
|
||||
- `type?: 'label' | 'link'`{lang="ts-type"}
|
||||
- `collapsible?: boolean`{lang="ts-type"}
|
||||
- `defaultOpen?: boolean`{lang="ts-type"}
|
||||
- `open?: boolean`{lang="ts-type"}
|
||||
- `value?: string`{lang="ts-type"}
|
||||
- `disabled?: boolean`{lang="ts-type"}
|
||||
- `class?: any`{lang="ts-type"}
|
||||
@@ -140,7 +144,7 @@ Each item can take a `children` array of objects with the following properties t
|
||||
Use the `orientation` prop to change the orientation of the NavigationMenu.
|
||||
|
||||
::note
|
||||
When orientation is `vertical`, a [Collapsible](/components/collapsible) component is used to display children. You can control the open state of each item using the `open` and `defaultOpen` properties.
|
||||
When orientation is `vertical`, a [Collapsible](/components/collapsible) component is used to display children. You can control the open state of each item using the `open` and `defaultOpen` properties. You can also use the `collapsible` property to control if the item is collapsible.
|
||||
::
|
||||
|
||||
::component-code
|
||||
|
||||
@@ -136,6 +136,21 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Tooltip :badge{label="Soon" class="align-text-top"}
|
||||
|
||||
Use the `tooltip` prop to display a [Tooltip](/components/tooltip) around the Slider thumbs with the current value. You can set it to `true` for default behavior or pass an object to customize it with any property from the [Tooltip](/components/tooltip#props) component.
|
||||
|
||||
::component-code
|
||||
---
|
||||
ignore:
|
||||
- defaultValue
|
||||
- tooltip
|
||||
props:
|
||||
defaultValue: 50
|
||||
tooltip: true
|
||||
---
|
||||
::
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to disable the Slider.
|
||||
|
||||
@@ -260,6 +260,30 @@ You can use the `expanded` prop to control the expandable state of the rows (can
|
||||
You could also add this action to the [`DropdownMenu`](/components/dropdown-menu) component inside the `actions` column.
|
||||
::
|
||||
|
||||
### With grouped rows
|
||||
|
||||
You can group rows based on a given column value and show/hide sub rows via some button added to the cell using the TanStack Table [Grouping APIs](https://tanstack.com/table/latest/docs/api/features/grouping).
|
||||
|
||||
#### Important parts:
|
||||
|
||||
* Add prop `grouping` to `UTable` component with an array of column ids you want to group by.
|
||||
* Add prop `grouping-options` to `UTable`. It must include `getGroupedRowModel`, you can import it from `@tanstack/vue-table` or implement your own.
|
||||
* Expand rows via `row.toggleExpanded()` method on any cell of the row. Keep in mind, it also toggles `#expanded` slot.
|
||||
* Use `aggregateFn` on column definition to define how to aggregate the rows.
|
||||
* `agregatedCell` renderer on column definition only works if there is no `cell` renderer.
|
||||
|
||||
::component-example
|
||||
---
|
||||
prettier: true
|
||||
collapse: true
|
||||
name: 'table-grouped-rows-example'
|
||||
highlights:
|
||||
- 159
|
||||
- 169
|
||||
class: '!p-0'
|
||||
---
|
||||
::
|
||||
|
||||
### With row selection
|
||||
|
||||
You can add a new column that renders a [Checkbox](/components/checkbox) component inside the `header` and `cell` to select rows using the TanStack Table [Row Selection APIs](https://tanstack.com/table/latest/docs/api/features/row-selection).
|
||||
|
||||
@@ -210,10 +210,6 @@ You can control the active item by using the `default-value` prop or the `v-mode
|
||||
|
||||
:component-example{name="tabs-model-value-example"}
|
||||
|
||||
::tip
|
||||
You can also pass the `value` of one of the items if provided.
|
||||
::
|
||||
|
||||
### With content slot
|
||||
|
||||
Use the `#content` slot to customize the content of each item.
|
||||
|
||||
@@ -188,7 +188,7 @@ name: 'toast-example'
|
||||
:toaster-position-example
|
||||
::
|
||||
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.vue#L77"}
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.config.ts#L3"}
|
||||
In this example, we use the `AppConfig` to configure the `position` prop of the `Toaster` component globally.
|
||||
::
|
||||
|
||||
@@ -206,7 +206,7 @@ name: 'toast-example'
|
||||
:toaster-duration-example
|
||||
::
|
||||
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.vue#L77"}
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.config.ts#L5"}
|
||||
In this example, we use the `AppConfig` to configure the `duration` prop of the `Toaster` component globally.
|
||||
::
|
||||
|
||||
@@ -228,7 +228,7 @@ name: 'toast-example'
|
||||
:toaster-expand-example
|
||||
::
|
||||
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.vue#L77"}
|
||||
::note{to="https://github.com/nuxt/ui/blob/v3/docs/app/app.config.ts#L4"}
|
||||
In this example, we use the `AppConfig` to configure the `expand` prop of the `Toaster` component globally.
|
||||
::
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ export default defineNuxtConfig({
|
||||
],
|
||||
|
||||
modules: [
|
||||
'../src/module',
|
||||
'@nuxt/ui-pro',
|
||||
'@nuxt/content',
|
||||
'@nuxt/image',
|
||||
|
||||
@@ -3,26 +3,26 @@
|
||||
"name": "@nuxt/ui-docs",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@ai-sdk/vue": "^1.2.8",
|
||||
"@ai-sdk/vue": "^1.2.11",
|
||||
"@iconify-json/logos": "^1.2.4",
|
||||
"@iconify-json/lucide": "^1.2.39",
|
||||
"@iconify-json/lucide": "^1.2.41",
|
||||
"@iconify-json/simple-icons": "^1.2.33",
|
||||
"@iconify-json/vscode-icons": "^1.2.20",
|
||||
"@nuxt/content": "^3.5.1",
|
||||
"@nuxt/image": "^1.10.0",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxt/ui-pro": "^3.1.0",
|
||||
"@nuxthub/core": "^0.8.25",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@a30de4d",
|
||||
"@nuxthub/core": "^0.8.27",
|
||||
"@nuxtjs/plausible": "^1.2.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"@rollup/plugin-yaml": "^4.1.2",
|
||||
"@vueuse/integrations": "^13.1.0",
|
||||
"@vueuse/nuxt": "^13.1.0",
|
||||
"ai": "^4.3.10",
|
||||
"ai": "^4.3.15",
|
||||
"capture-website": "^4.2.0",
|
||||
"joi": "^17.13.3",
|
||||
"motion-v": "^1.0.0",
|
||||
"nuxt": "^3.16.2",
|
||||
"motion-v": "^1.0.2",
|
||||
"nuxt": "^3.17.2",
|
||||
"nuxt-component-meta": "^0.11.0",
|
||||
"nuxt-llms": "^0.1.2",
|
||||
"nuxt-og-image": "^5.1.3",
|
||||
@@ -31,12 +31,12 @@
|
||||
"sortablejs": "^1.15.6",
|
||||
"superstruct": "^2.0.2",
|
||||
"ufo": "^1.6.1",
|
||||
"valibot": "^1.0.0",
|
||||
"workers-ai-provider": "^0.3.0",
|
||||
"valibot": "^1.1.0",
|
||||
"workers-ai-provider": "^0.3.1",
|
||||
"yup": "^1.6.1",
|
||||
"zod": "^3.24.3"
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wrangler": "^4.13.2"
|
||||
"wrangler": "^4.14.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,33 @@ const parseBoolean = (value?: string): boolean => value === 'true'
|
||||
|
||||
function getComponentMeta(componentName: string) {
|
||||
const pascalCaseName = componentName.charAt(0).toUpperCase() + componentName.slice(1)
|
||||
const metaComponentName = `U${pascalCaseName}`
|
||||
|
||||
const strategies = [
|
||||
`U${pascalCaseName}`,
|
||||
`Prose${pascalCaseName}`,
|
||||
pascalCaseName
|
||||
]
|
||||
|
||||
let componentMeta: any
|
||||
let finalMetaComponentName: string = pascalCaseName
|
||||
|
||||
for (const nameToTry of strategies) {
|
||||
finalMetaComponentName = nameToTry
|
||||
const metaAttempt = (meta as Record<string, any>)[nameToTry]?.meta
|
||||
if (metaAttempt) {
|
||||
componentMeta = metaAttempt
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!componentMeta) {
|
||||
console.warn(`[getComponentMeta] Metadata not found for ${pascalCaseName} using strategies: U, Prose, or no prefix. Last tried: ${finalMetaComponentName}`)
|
||||
}
|
||||
|
||||
return {
|
||||
pascalCaseName,
|
||||
metaComponentName,
|
||||
componentMeta: (meta as Record<string, any>)[metaComponentName]?.meta
|
||||
metaComponentName: finalMetaComponentName,
|
||||
componentMeta
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +190,7 @@ function emitItemHandler(event: any): string {
|
||||
const generateThemeConfig = ({ pro, prose, componentName }: ThemeConfig) => {
|
||||
const computedTheme = pro ? (prose ? themePro.prose : themePro) : theme
|
||||
const componentTheme = computedTheme[componentName as keyof typeof computedTheme]
|
||||
|
||||
return {
|
||||
[pro ? 'uiPro' : 'ui']: prose
|
||||
? { prose: { [componentName]: componentTheme } }
|
||||
@@ -284,10 +307,14 @@ export default defineNitroPlugin((nitroApp) => {
|
||||
const componentName = camelCase(doc.title)
|
||||
|
||||
visitAndReplace(doc, 'component-theme', (node) => {
|
||||
const attributes = node[1] as ComponentAttributes
|
||||
const attributes = node[1] as Record<string, string>
|
||||
const mdcSpecificName = attributes?.slug
|
||||
|
||||
const finalComponentName = mdcSpecificName ? camelCase(mdcSpecificName) : componentName
|
||||
|
||||
const pro = parseBoolean(attributes[':pro'])
|
||||
const prose = parseBoolean(attributes[':prose'])
|
||||
const appConfig = generateThemeConfig({ pro, prose, componentName })
|
||||
const appConfig = generateThemeConfig({ pro, prose, componentName: finalComponentName })
|
||||
|
||||
replaceNodeWithPre(
|
||||
node,
|
||||
@@ -322,14 +349,23 @@ export default defineNitroPlugin((nitroApp) => {
|
||||
})
|
||||
|
||||
visitAndReplace(doc, 'component-props', (node) => {
|
||||
const { pascalCaseName, componentMeta } = getComponentMeta(componentName)
|
||||
const attributes = node[1] as Record<string, string>
|
||||
const mdcSpecificName = attributes?.name
|
||||
const isProse = parseBoolean(attributes[':prose'])
|
||||
|
||||
const finalComponentName = mdcSpecificName ? camelCase(mdcSpecificName) : componentName
|
||||
|
||||
const { pascalCaseName, componentMeta } = getComponentMeta(finalComponentName)
|
||||
|
||||
if (!componentMeta?.props) return
|
||||
|
||||
const interfaceName = isProse ? `Prose${pascalCaseName}Props` : `${pascalCaseName}Props`
|
||||
|
||||
const interfaceCode = generateTSInterface(
|
||||
`${pascalCaseName}Props`,
|
||||
interfaceName,
|
||||
Object.values(componentMeta.props),
|
||||
propItemHandler,
|
||||
`Props for the ${pascalCaseName} component`
|
||||
`Props for the ${isProse ? 'Prose' : ''}${pascalCaseName} component`
|
||||
)
|
||||
replaceNodeWithPre(node, 'ts', interfaceCode)
|
||||
})
|
||||
|
||||
37
package.json
37
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nuxt/ui",
|
||||
"description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"packageManager": "pnpm@10.10.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -96,12 +96,12 @@
|
||||
"scripts": {
|
||||
"build": "nuxt-module-build build",
|
||||
"prepack": "pnpm build",
|
||||
"dev": "nuxi dev playground",
|
||||
"dev": "nuxi dev playground --uiDev",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:vue": "vite playground-vue",
|
||||
"dev:vue": "vite playground-vue -- --uiDev",
|
||||
"dev:vue:build": "vite build playground-vue",
|
||||
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground && nuxi prepare docs && vite build playground-vue",
|
||||
"docs": "nuxi dev docs",
|
||||
"docs": "nuxi dev docs --uiDev",
|
||||
"docs:build": "nuxi build docs",
|
||||
"docs:prepare": "nuxt-component-meta docs",
|
||||
"lint": "eslint .",
|
||||
@@ -117,12 +117,12 @@
|
||||
"@internationalized/number": "^3.6.1",
|
||||
"@nuxt/fonts": "^0.11.2",
|
||||
"@nuxt/icon": "^1.12.0",
|
||||
"@nuxt/kit": "^3.16.2",
|
||||
"@nuxt/schema": "^3.16.2",
|
||||
"@nuxt/kit": "^3.17.2",
|
||||
"@nuxt/schema": "^3.17.2",
|
||||
"@nuxtjs/color-mode": "^3.5.2",
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@tailwindcss/postcss": "^4.1.4",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"@tailwindcss/postcss": "^4.1.5",
|
||||
"@tailwindcss/vite": "^4.1.5",
|
||||
"@tanstack/vue-table": "^8.21.3",
|
||||
"@unhead/vue": "^2.0.8",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
@@ -144,28 +144,29 @@
|
||||
"mlly": "^1.7.4",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"reka-ui": "^2.2.0",
|
||||
"reka-ui": "^2.2.1",
|
||||
"scule": "^1.3.0",
|
||||
"tailwind-variants": "^1.0.0",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"tailwindcss": "^4.1.5",
|
||||
"tinyglobby": "^0.2.13",
|
||||
"unplugin": "^2.3.2",
|
||||
"unplugin-auto-import": "^19.1.2",
|
||||
"unplugin-auto-import": "^19.2.0",
|
||||
"unplugin-vue-components": "^28.5.0",
|
||||
"vaul-vue": "^0.4.1"
|
||||
"vaul-vue": "^0.4.1",
|
||||
"vue-component-type-helpers": "^2.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint-config": "^1.3.0",
|
||||
"@nuxt/module-builder": "^1.0.1",
|
||||
"@nuxt/test-utils": "^3.17.2",
|
||||
"@nuxt/test-utils": "^3.18.0",
|
||||
"@release-it/conventional-changelog": "^10.0.1",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"embla-carousel": "^8.6.0",
|
||||
"eslint": "^9.25.1",
|
||||
"happy-dom": "^17.4.4",
|
||||
"nuxt": "^3.16.2",
|
||||
"release-it": "^19.0.1",
|
||||
"vitest": "^3.1.2",
|
||||
"eslint": "^9.26.0",
|
||||
"happy-dom": "^17.4.6",
|
||||
"nuxt": "^3.17.2",
|
||||
"release-it": "^19.0.2",
|
||||
"vitest": "^3.1.3",
|
||||
"vitest-environment-nuxt": "^1.0.1",
|
||||
"vue-tsc": "^2.2.10"
|
||||
},
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=public-sans:400,500,600,700" rel="stylesheet" />
|
||||
<title>Nuxt UI - Vue Playground</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
"@nuxt/ui": "latest",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.1",
|
||||
"zod": "^3.24.3"
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.3",
|
||||
"vite": "^6.3.5",
|
||||
"vue-tsc": "^2.2.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
"typecheck": "nuxt typecheck"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.39",
|
||||
"@iconify-json/lucide": "^1.2.41",
|
||||
"@iconify-json/simple-icons": "^1.2.33",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxthub/core": "^0.8.25",
|
||||
"nuxt": "^3.16.2",
|
||||
"zod": "^3.24.3"
|
||||
"@nuxthub/core": "^0.8.27",
|
||||
"nuxt": "^3.17.2",
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3",
|
||||
|
||||
4023
pnpm-lock.yaml
generated
4023
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,6 @@
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
},
|
||||
"ignoreDeps": [
|
||||
"vue-tsc"
|
||||
],
|
||||
"baseBranches": ["v2", "v3"],
|
||||
"packageRules": [{
|
||||
"matchBaseBranches": ["v3"],
|
||||
@@ -19,6 +16,11 @@
|
||||
"@tailwindcss/postcss",
|
||||
"@tailwindcss/vite"
|
||||
]
|
||||
}, {
|
||||
"groupName": "reka-ui",
|
||||
"matchPackageNames": [
|
||||
"reka-ui"
|
||||
]
|
||||
}, {
|
||||
"matchDepTypes": ["peerDependencies"],
|
||||
"enabled": false
|
||||
|
||||
@@ -93,7 +93,7 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
|
||||
await registerModule('@nuxt/icon', 'icon', { cssLayer: 'components' })
|
||||
if (options.fonts) {
|
||||
await registerModule('@nuxt/fonts', 'fonts', { experimental: { processCSSVariables: true } })
|
||||
await registerModule('@nuxt/fonts', 'fonts', {})
|
||||
}
|
||||
if (options.colorMode) {
|
||||
await registerModule('@nuxtjs/color-mode', 'colorMode', { classSuffix: '', disableTransition: true })
|
||||
|
||||
@@ -16,6 +16,7 @@ export default function PluginsPlugin(options: NuxtUIOptions) {
|
||||
const plugins = globSync(['**/*', '!*.d.ts'], { cwd: join(runtimeDir, 'plugins'), absolute: true })
|
||||
|
||||
plugins.unshift(resolvePathSync('../runtime/vue/plugins/head', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
|
||||
plugins.push(resolvePathSync('../runtime/vue/plugins/colors', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
|
||||
if (options.colorMode) {
|
||||
plugins.push(resolvePathSync('../runtime/vue/plugins/color-mode', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.accordion ||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<AccordionRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<AccordionItem
|
||||
v-for="(item, index) in props.items"
|
||||
v-slot="{ open }"
|
||||
|
||||
@@ -97,7 +97,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.alert || {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :data-orientation="orientation" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :data-orientation="orientation" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<slot name="leading">
|
||||
<UAvatar v-if="avatar" :size="((props.ui?.avatarSize || ui.avatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
|
||||
<UIcon v-else-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
|
||||
@@ -81,7 +81,7 @@ function onError() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })" :style="props.style">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })" :style="props.style">
|
||||
<component
|
||||
:is="ImageComponent"
|
||||
v-if="src && !error"
|
||||
|
||||
@@ -93,7 +93,7 @@ provide(avatarGroupInjectionKey, computed(() => ({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<UAvatar v-if="hiddenCount > 0" :text="`+${hiddenCount}`" :class="ui.base({ class: props.ui?.base })" />
|
||||
<component :is="avatar" v-for="(avatar, count) in visibleAvatars" :key="count" :class="ui.base({ class: props.ui?.base })" />
|
||||
</Primitive>
|
||||
|
||||
@@ -65,14 +65,14 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.badge || {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.base({ class: [props.class, props.ui?.base] })">
|
||||
<Primitive :as="as" :class="ui.base({ class: [props.ui?.base, props.class] })">
|
||||
<slot name="leading">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
<UAvatar v-else-if="!!avatar" :size="((props.ui?.leadingAvatarSize || ui.leadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.leadingAvatar({ class: props.ui?.leadingAvatar })" />
|
||||
</slot>
|
||||
|
||||
<slot>
|
||||
<span v-if="label" :class="ui.label({ class: props.ui?.label })">
|
||||
<span v-if="label !== undefined && label !== null" :class="ui.label({ class: props.ui?.label })">
|
||||
{{ label }}
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -81,7 +81,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.breadcrumb |
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" aria-label="breadcrumb" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" aria-label="breadcrumb" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<ol :class="ui.list({ class: props.ui?.list })">
|
||||
<template v-for="(item, index) in items" :key="index">
|
||||
<li :class="ui.item({ class: props.ui?.item })">
|
||||
|
||||
@@ -123,7 +123,7 @@ const ui = computed(() => tv({
|
||||
v-slot="{ active, ...slotProps }"
|
||||
:type="type"
|
||||
:disabled="disabled || isLoading"
|
||||
:class="ui.base({ class: [props.class, props.ui?.base] })"
|
||||
:class="ui.base({ class: [props.ui?.base, props.class] })"
|
||||
v-bind="omit(linkProps, ['type', 'disabled', 'onClick'])"
|
||||
custom
|
||||
>
|
||||
@@ -143,7 +143,7 @@ const ui = computed(() => tv({
|
||||
</slot>
|
||||
|
||||
<slot>
|
||||
<span v-if="label" :class="ui.label({ class: props.ui?.label, active })">
|
||||
<span v-if="label !== undefined && label !== null" :class="ui.label({ class: props.ui?.label, active })">
|
||||
{{ label }}
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
@@ -157,7 +157,7 @@ const Calendar = computed(() => props.range ? RangeCalendar : SingleCalendar)
|
||||
:default-value="defaultValue"
|
||||
:locale="locale"
|
||||
:dir="dir"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
>
|
||||
<Calendar.Header :class="ui.header({ class: props.ui?.header })">
|
||||
<Calendar.Prev v-if="props.yearControls" :prev-page="(date: DateValue) => paginateYear(date, -1)" :aria-label="t('calendar.prevYear')" as-child>
|
||||
|
||||
@@ -43,7 +43,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.card || {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div v-if="!!slots.header" :class="ui.header({ class: props.ui?.header })">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
|
||||
@@ -278,7 +278,7 @@ defineExpose({
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
tabindex="0"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
@keydown="onKeyDown"
|
||||
>
|
||||
<div ref="emblaRef" :class="ui.viewport({ class: props.ui?.viewport })">
|
||||
|
||||
@@ -101,7 +101,7 @@ function onUpdate(value: any) {
|
||||
|
||||
<!-- eslint-disable vue/no-template-shadow -->
|
||||
<template>
|
||||
<Primitive :as="variant === 'list' ? as : Label" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="variant === 'list' ? as : Label" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<CheckboxRoot
|
||||
:id="id"
|
||||
|
||||
@@ -74,6 +74,7 @@ import { useAppConfig } from '#imports'
|
||||
import { useFormField } from '../composables/useFormField'
|
||||
import { get, omit } from '../utils'
|
||||
import { tv } from '../utils/tv'
|
||||
import UCheckbox from './Checkbox.vue'
|
||||
|
||||
const props = withDefaults(defineProps<CheckboxGroupProps<T>>(), {
|
||||
valueKey: 'value',
|
||||
@@ -152,7 +153,7 @@ function onUpdate(value: any) {
|
||||
v-bind="rootProps"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
@update:model-value="onUpdate"
|
||||
>
|
||||
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">
|
||||
|
||||
@@ -74,7 +74,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.chip || {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<Slot v-bind="$attrs">
|
||||
<slot />
|
||||
</Slot>
|
||||
|
||||
@@ -46,7 +46,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.collapsible
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleRoot v-slot="{ open }" v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<CollapsibleRoot v-slot="{ open }" v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<CollapsibleTrigger v-if="!!slots.default" as-child>
|
||||
<slot :open="open" />
|
||||
</CollapsibleTrigger>
|
||||
|
||||
@@ -263,7 +263,7 @@ const trackThumbStyle = computed(() => ({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })" :data-disabled="disabled ? true : undefined">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })" :data-disabled="disabled ? true : undefined">
|
||||
<div :class="ui.picker({ class: props.ui?.picker })">
|
||||
<div
|
||||
ref="selectorRef"
|
||||
|
||||
@@ -249,7 +249,7 @@ const groups = computed(() => {
|
||||
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<ListboxRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<ListboxRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<ListboxFilter v-model="searchTerm" as-child>
|
||||
<UInput
|
||||
:placeholder="placeholder || t('commandPalette.placeholder')"
|
||||
|
||||
@@ -90,7 +90,7 @@ provide(formFieldInjectionKey, computed(() => ({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<div v-if="label || !!slots.label" :class="ui.labelWrapper({ class: props.ui?.labelWrapper })">
|
||||
<Label :for="id" :class="ui.label({ class: props.ui?.label })">
|
||||
|
||||
@@ -163,7 +163,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<input
|
||||
:id="id"
|
||||
ref="inputRef"
|
||||
|
||||
@@ -406,7 +406,7 @@ defineExpose({
|
||||
v-bind="rootProps"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
:as-child="!!multiple"
|
||||
ignore-filter
|
||||
@update:model-value="onUpdate"
|
||||
|
||||
@@ -145,7 +145,7 @@ defineExpose({
|
||||
<NumberFieldRoot
|
||||
v-bind="rootProps"
|
||||
:id="id"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:locale="locale"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { NavigationMenuRootProps, NavigationMenuRootEmits, NavigationMenuContentProps, NavigationMenuContentEmits, CollapsibleRootProps } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import theme from '#build/ui/navigation-menu'
|
||||
import type { AvatarProps, BadgeProps, LinkProps } from '../types'
|
||||
import type { AvatarProps, BadgeProps, LinkProps, TooltipProps } from '../types'
|
||||
import type { ArrayOrNested, DynamicSlots, MergeTypes, NestedItem, EmitsToProps, ComponentConfig } from '../types/utils'
|
||||
|
||||
type NavigationMenu = ComponentConfig<typeof theme, AppConfig, 'navigationMenu'>
|
||||
@@ -26,6 +26,12 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
|
||||
* `{ size: 'sm', color: 'neutral', variant: 'outline' }`{lang="ts-type"}
|
||||
*/
|
||||
badge?: string | number | BadgeProps
|
||||
/**
|
||||
* Display a tooltip on the item.
|
||||
* Only works when `type` is `link`.
|
||||
* `{ content: { side: 'right' } }`{lang="ts-type"}
|
||||
*/
|
||||
tooltip?: TooltipProps
|
||||
/**
|
||||
* @IconifyIcon
|
||||
*/
|
||||
@@ -38,6 +44,12 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
|
||||
type?: 'label' | 'link'
|
||||
slot?: string
|
||||
value?: string
|
||||
/**
|
||||
* Make the item collapsible.
|
||||
* Only works when `orientation` is `vertical`.
|
||||
* @defaultValue true
|
||||
*/
|
||||
collapsible?: boolean
|
||||
children?: NavigationMenuChildItem[]
|
||||
onSelect?(e: Event): void
|
||||
[key: string]: any
|
||||
@@ -143,6 +155,7 @@ import UAvatar from './Avatar.vue'
|
||||
import UIcon from './Icon.vue'
|
||||
import UBadge from './Badge.vue'
|
||||
import UCollapsible from './Collapsible.vue'
|
||||
import UTooltip from './Tooltip.vue'
|
||||
|
||||
const props = withDefaults(defineProps<NavigationMenuProps<T>>(), {
|
||||
orientation: 'horizontal',
|
||||
@@ -229,7 +242,7 @@ const lists = computed<NavigationMenuItem[][]>(() =>
|
||||
:class="ui.linkTrailingBadge({ class: props.ui?.linkTrailingBadge })"
|
||||
/>
|
||||
|
||||
<UIcon v-if="(orientation === 'horizontal' && (item.children?.length || !!slots[(item.slot ? `${item.slot}-content` : 'item-content') as keyof NavigationMenuSlots<T>])) || (orientation === 'vertical' && item.children?.length)" :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.linkTrailingIcon({ class: props.ui?.linkTrailingIcon, active })" />
|
||||
<UIcon v-if="(orientation === 'horizontal' && (item.children?.length || !!slots[(item.slot ? `${item.slot}-content` : 'item-content') as keyof NavigationMenuSlots<T>])) || (orientation === 'vertical' && item.children?.length && item.collapsible !== false)" :name="item.trailingIcon || trailingIcon || appConfig.ui.icons.chevronDown" :class="ui.linkTrailingIcon({ class: props.ui?.linkTrailingIcon, active })" />
|
||||
<UIcon v-else-if="item.trailingIcon" :name="item.trailingIcon" :class="ui.linkTrailingIcon({ class: props.ui?.linkTrailingIcon, active })" />
|
||||
</slot>
|
||||
</span>
|
||||
@@ -238,17 +251,18 @@ const lists = computed<NavigationMenuItem[][]>(() =>
|
||||
|
||||
<DefineItemTemplate v-slot="{ item, index, level = 0 }">
|
||||
<component
|
||||
:is="(orientation === 'vertical' && item.children?.length && !collapsed) ? UCollapsible : NavigationMenuItem"
|
||||
:is="(orientation === 'vertical' && item.children?.length) ? UCollapsible : NavigationMenuItem"
|
||||
as="li"
|
||||
:value="item.value || String(index)"
|
||||
:default-open="item.defaultOpen"
|
||||
:unmount-on-hide="(orientation === 'vertical' && item.children?.length && !collapsed) ? unmountOnHide : undefined"
|
||||
:disabled="(orientation === 'vertical' && item.children?.length) ? item.collapsible === false : undefined"
|
||||
:unmount-on-hide="(orientation === 'vertical' && item.children?.length) ? unmountOnHide : undefined"
|
||||
:open="item.open"
|
||||
>
|
||||
<div v-if="orientation === 'vertical' && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
||||
<ReuseLinkTemplate :item="item" :index="index" />
|
||||
</div>
|
||||
<ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length && !collapsed) ? {} : pickLinkProps(item as Omit<NavigationMenuItem, 'type'>)" custom>
|
||||
<ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length && item.collapsible !== false) ? {} : pickLinkProps(item as Omit<NavigationMenuItem, 'type'>)" custom>
|
||||
<component
|
||||
:is="(orientation === 'horizontal' && (item.children?.length || !!slots[(item.slot ? `${item.slot}-content` : 'item-content') as keyof NavigationMenuSlots<T>])) ? NavigationMenuTrigger : NavigationMenuLink"
|
||||
as-child
|
||||
@@ -256,7 +270,12 @@ const lists = computed<NavigationMenuItem[][]>(() =>
|
||||
:disabled="item.disabled"
|
||||
@select="item.onSelect"
|
||||
>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: orientation === 'horizontal' || level > 0 })">
|
||||
<UTooltip v-if="!!item.tooltip" :content="{ side: 'right' }" v-bind="item.tooltip">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: orientation === 'horizontal' || level > 0 })">
|
||||
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" />
|
||||
</ULinkBase>
|
||||
</UTooltip>
|
||||
<ULinkBase v-else v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: orientation === 'horizontal' || level > 0 })">
|
||||
<ReuseLinkTemplate :item="item" :active="active || item.active" :index="index" />
|
||||
</ULinkBase>
|
||||
</component>
|
||||
@@ -289,7 +308,7 @@ const lists = computed<NavigationMenuItem[][]>(() =>
|
||||
</NavigationMenuContent>
|
||||
</ULink>
|
||||
|
||||
<template v-if="orientation === 'vertical' && item.children?.length && !collapsed" #content>
|
||||
<template v-if="orientation === 'vertical' && item.children?.length " #content>
|
||||
<ul :class="ui.childList({ class: props.ui?.childList })">
|
||||
<ReuseItemTemplate
|
||||
v-for="(childItem, childIndex) in item.children"
|
||||
@@ -304,7 +323,7 @@ const lists = computed<NavigationMenuItem[][]>(() =>
|
||||
</component>
|
||||
</DefineItemTemplate>
|
||||
|
||||
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<slot name="list-leading" />
|
||||
|
||||
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
|
||||
|
||||
@@ -140,7 +140,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.pagination |
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<PaginationList v-slot="{ items }" :class="ui.list({ class: props.ui?.list })">
|
||||
<PaginationFirst v-if="showControls || !!slots.first" as-child :class="ui.first({ class: props.ui?.first })">
|
||||
<slot name="first">
|
||||
|
||||
@@ -113,7 +113,7 @@ defineExpose({
|
||||
v-bind="{ ...rootProps, ...ariaAttrs }"
|
||||
:id="id"
|
||||
:name="name"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
@update:model-value="emitFormInput()"
|
||||
@complete="onComplete"
|
||||
>
|
||||
|
||||
@@ -167,7 +167,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.progress ||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div v-if="!isIndeterminate && (status || !!slots.status)" :class="ui.status({ class: props.ui?.status })" :style="statusStyle">
|
||||
<slot name="status" :percent="percent">
|
||||
{{ percent }}%
|
||||
|
||||
@@ -166,7 +166,7 @@ function onUpdate(value: any) {
|
||||
v-bind="rootProps"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
@update:model-value="onUpdate"
|
||||
>
|
||||
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">
|
||||
|
||||
@@ -21,7 +21,7 @@ interface SelectItemBase {
|
||||
* @defaultValue 'item'
|
||||
*/
|
||||
type?: 'label' | 'separator' | 'item'
|
||||
value?: string | number
|
||||
value?: AcceptableValue | boolean
|
||||
disabled?: boolean
|
||||
onSelect?(e?: Event): void
|
||||
[key: string]: any
|
||||
@@ -238,7 +238,7 @@ function isSelectItem(item: SelectItem): item is SelectItemBase {
|
||||
@update:model-value="onUpdate"
|
||||
@update:open="onUpdateOpen"
|
||||
>
|
||||
<SelectTrigger :id="id" :class="ui.base({ class: [props.class, props.ui?.base] })" v-bind="{ ...$attrs, ...ariaAttrs }">
|
||||
<SelectTrigger :id="id" :class="ui.base({ class: [props.ui?.base, props.class] })" v-bind="{ ...$attrs, ...ariaAttrs }">
|
||||
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
|
||||
@@ -373,7 +373,7 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
|
||||
@update:open="onUpdateOpen"
|
||||
>
|
||||
<ComboboxAnchor as-child>
|
||||
<ComboboxTrigger :class="ui.base({ class: [props.class, props.ui?.base] })" tabindex="0">
|
||||
<ComboboxTrigger :class="ui.base({ class: [props.ui?.base, props.class] })" tabindex="0">
|
||||
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
|
||||
@@ -75,7 +75,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.separator ||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Separator v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Separator v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.border({ class: props.ui?.border })" />
|
||||
|
||||
<template v-if="label || icon || avatar || !!slots.default">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { SliderRootProps } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import theme from '#build/ui/slider'
|
||||
import type { TooltipProps } from '../types'
|
||||
import type { ComponentConfig } from '../types/utils'
|
||||
|
||||
type Slider = ComponentConfig<typeof theme, AppConfig, 'slider'>
|
||||
@@ -25,6 +26,12 @@ export interface SliderProps extends Pick<SliderRootProps, 'name' | 'disabled' |
|
||||
* @defaultValue 'horizontal'
|
||||
*/
|
||||
orientation?: SliderRootProps['orientation']
|
||||
/**
|
||||
* Display a tooltip around the slider thumbs with the current value.
|
||||
* `{ disableClosingTrigger: true }`{lang="ts-type"}
|
||||
* @defaultValue false
|
||||
*/
|
||||
tooltip?: boolean | TooltipProps
|
||||
/** The value of the slider when initially rendered. Use when you do not need to control the state of the slider. */
|
||||
defaultValue?: number | number[]
|
||||
class?: any
|
||||
@@ -44,6 +51,7 @@ import { reactivePick } from '@vueuse/core'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { useFormField } from '../composables/useFormField'
|
||||
import { tv } from '../utils/tv'
|
||||
import UTooltip from './Tooltip.vue'
|
||||
|
||||
const props = withDefaults(defineProps<SliderProps>(), {
|
||||
min: 0,
|
||||
@@ -80,7 +88,7 @@ const sliderValue = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const thumbsCount = computed(() => sliderValue.value?.length ?? 1)
|
||||
const thumbs = computed(() => sliderValue.value?.length ?? 1)
|
||||
|
||||
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.slider || {}) })({
|
||||
disabled: disabled.value,
|
||||
@@ -104,7 +112,7 @@ function onChange(value: any) {
|
||||
v-model="sliderValue"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
:default-value="defaultSliderValue"
|
||||
@update:model-value="emitFormInput()"
|
||||
@value-commit="onChange"
|
||||
@@ -113,6 +121,16 @@ function onChange(value: any) {
|
||||
<SliderRange :class="ui.range({ class: props.ui?.range })" />
|
||||
</SliderTrack>
|
||||
|
||||
<SliderThumb v-for="count in thumbsCount" :key="count" :class="ui.thumb({ class: props.ui?.thumb })" />
|
||||
<template v-for="thumb in thumbs" :key="thumb">
|
||||
<UTooltip
|
||||
v-if="!!tooltip"
|
||||
:text="thumbs > 1 ? String(sliderValue?.[thumb - 1]) : String(sliderValue)"
|
||||
disable-closing-trigger
|
||||
v-bind="(typeof tooltip === 'object' ? tooltip : {})"
|
||||
>
|
||||
<SliderThumb :class="ui.thumb({ class: props.ui?.thumb })" />
|
||||
</UTooltip>
|
||||
<SliderThumb v-else :class="ui.thumb({ class: props.ui?.thumb })" />
|
||||
</template>
|
||||
</SliderRoot>
|
||||
</template>
|
||||
|
||||
@@ -129,7 +129,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<StepperRoot v-bind="rootProps" v-model="currentStepIndex" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<StepperRoot v-bind="rootProps" v-model="currentStepIndex" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.header({ class: props.ui?.header })">
|
||||
<StepperItem
|
||||
v-for="(item, count) in items"
|
||||
@@ -157,12 +157,12 @@ defineExpose({
|
||||
</div>
|
||||
|
||||
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
||||
<StepperTitle :class="ui.title({ class: props.ui?.title })">
|
||||
<StepperTitle as="div" :class="ui.title({ class: props.ui?.title })">
|
||||
<slot name="title" :item="item">
|
||||
{{ item.title }}
|
||||
</slot>
|
||||
</StepperTitle>
|
||||
<StepperDescription :class="ui.description({ class: props.ui?.description })">
|
||||
<StepperDescription as="div" :class="ui.description({ class: props.ui?.description })">
|
||||
<slot name="description" :item="item">
|
||||
{{ item.description }}
|
||||
</slot>
|
||||
|
||||
@@ -96,7 +96,7 @@ function onUpdate(value: any) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<div :class="ui.container({ class: props.ui?.container })">
|
||||
<SwitchRoot
|
||||
:id="id"
|
||||
|
||||
@@ -338,7 +338,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<table ref="tableRef" :class="ui.base({ class: [props.ui?.base] })">
|
||||
<caption v-if="caption || !!slots.caption" :class="ui.caption({ class: [props.ui?.caption] })">
|
||||
<slot name="caption">
|
||||
|
||||
@@ -109,7 +109,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.tabs || {})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TabsRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<TabsRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<TabsList :class="ui.list({ class: props.ui?.list })">
|
||||
<TabsIndicator :class="ui.indicator({ class: props.ui?.indicator })" />
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
||||
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||
<textarea
|
||||
:id="id"
|
||||
ref="textareaRef"
|
||||
|
||||
@@ -116,7 +116,7 @@ defineExpose({
|
||||
v-slot="{ remaining, duration }"
|
||||
v-bind="rootProps"
|
||||
:data-orientation="orientation"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
:style="{ '--height': height }"
|
||||
>
|
||||
<slot name="leading">
|
||||
|
||||
@@ -131,7 +131,7 @@ function getOffset(index: number) {
|
||||
<ToastPortal v-bind="portalProps">
|
||||
<ToastViewport
|
||||
:data-expanded="expanded"
|
||||
:class="ui.viewport({ class: [props.class, props.ui?.viewport] })"
|
||||
:class="ui.viewport({ class: [props.ui?.viewport, props.class] })"
|
||||
:style="{
|
||||
'--scale-factor': '0.05',
|
||||
'--translate-factor': position?.startsWith('top') ? '1px' : '-1px',
|
||||
|
||||
@@ -198,7 +198,7 @@ const defaultExpanded = computed(() =>
|
||||
|
||||
<TreeRoot
|
||||
v-bind="(rootProps as unknown as TreeRootProps<NestedItem<T>>)"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
:class="ui.root({ class: [props.ui?.root, props.class] })"
|
||||
:get-key="getItemValue"
|
||||
:default-expanded="defaultExpanded"
|
||||
:selection-behavior="selectionBehavior"
|
||||
|
||||
@@ -122,6 +122,12 @@ function _useOverlay() {
|
||||
return overlay
|
||||
}
|
||||
|
||||
const isOpen = (id: symbol): boolean => {
|
||||
const overlay = getOverlay(id)
|
||||
|
||||
return overlay.isOpen
|
||||
}
|
||||
|
||||
return {
|
||||
overlays,
|
||||
open,
|
||||
@@ -129,7 +135,8 @@ function _useOverlay() {
|
||||
closeAll,
|
||||
create,
|
||||
patch,
|
||||
unMount
|
||||
unMount,
|
||||
isOpen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ const ui = computed(() => tv({
|
||||
}))
|
||||
|
||||
const isExternal = computed(() => {
|
||||
if (props.external) return true
|
||||
if (!props.to) return false
|
||||
return typeof props.to === 'string' && hasProtocol(props.to, { acceptRelative: true })
|
||||
})
|
||||
@@ -110,14 +111,14 @@ const linkClass = computed(() => {
|
||||
})
|
||||
|
||||
const page = usePage()
|
||||
const url = computed(() => props.to ?? props.href ?? '#')
|
||||
const url = computed(() => props.to ?? props.href ?? '')
|
||||
|
||||
const isActive = computed(() => props.active || (props.exact ? url.value === props.href : page?.url.startsWith(url.value)))
|
||||
const isActive = computed(() => props.active || (!!url.value && (props.exact ? url.value === props.href : page?.url.startsWith(url.value))))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="!isExternal">
|
||||
<InertiaLink v-bind="routerLinkProps" :href="url" custom>
|
||||
<template v-if="!isExternal && !!url">
|
||||
<InertiaLink v-bind="routerLinkProps" :href="url">
|
||||
<template v-if="custom">
|
||||
<slot
|
||||
v-bind="{
|
||||
|
||||
@@ -1,43 +1,13 @@
|
||||
import { computed } from 'vue'
|
||||
import colors from 'tailwindcss/colors'
|
||||
import type { UseHeadInput } from '@unhead/vue/types'
|
||||
import { defineNuxtPlugin, useAppConfig, useNuxtApp, useHead } from '#imports'
|
||||
|
||||
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const
|
||||
|
||||
function getColor(color: keyof typeof colors, shade: typeof shades[number]): string {
|
||||
if (color in colors && typeof colors[color] === 'object' && shade in colors[color]) {
|
||||
return colors[color][shade] as string
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function generateShades(key: string, value: string) {
|
||||
return `${shades.map(shade => `--ui-color-${key}-${shade}: var(--color-${value === 'neutral' ? 'old-neutral' : value}-${shade}, ${getColor(value as keyof typeof colors, shade)});`).join('\n ')}`
|
||||
}
|
||||
function generateColor(key: string, shade: number) {
|
||||
return `--ui-${key}: var(--ui-color-${key}-${shade});`
|
||||
}
|
||||
import { generateColorStyles } from '../utils/colors'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const appConfig = useAppConfig()
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
const root = computed(() => {
|
||||
const { neutral, ...colors } = appConfig.ui.colors
|
||||
|
||||
return `@layer base {
|
||||
:root {
|
||||
${Object.entries(appConfig.ui.colors).map(([key, value]: [string, string]) => generateShades(key, value)).join('\n ')}
|
||||
}
|
||||
:root, .light {
|
||||
${Object.keys(colors).map(key => generateColor(key, 500)).join('\n ')}
|
||||
}
|
||||
.dark {
|
||||
${Object.keys(colors).map(key => generateColor(key, 400)).join('\n ')}
|
||||
}
|
||||
}`
|
||||
})
|
||||
const root = computed(() => generateColorStyles(appConfig.ui.colors))
|
||||
|
||||
// Head
|
||||
const headData: UseHeadInput = {
|
||||
|
||||
63
src/runtime/types/tv.ts
Normal file
63
src/runtime/types/tv.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { ClassValue, TVVariants, TVCompoundVariants, TVDefaultVariants } from 'tailwind-variants'
|
||||
|
||||
/**
|
||||
* Defines the AppConfig object based on the tailwind-variants configuration.
|
||||
*/
|
||||
export type TVConfig<T extends Record<string, any>> = {
|
||||
[P in keyof T]?: {
|
||||
[K in keyof T[P]as K extends 'base' | 'slots' | 'variants' | 'compoundVariants' | 'defaultVariants' ? K : never]?: K extends 'base' ? ClassValue
|
||||
: K extends 'slots' ? {
|
||||
[S in keyof T[P]['slots']]?: ClassValue
|
||||
}
|
||||
: K extends 'variants' ? TVVariants<T[P]['slots'], ClassValue, T[P]['variants']>
|
||||
: K extends 'compoundVariants' ? TVCompoundVariants<T[P]['variants'], T[P]['slots'], ClassValue, object, undefined>
|
||||
: K extends 'defaultVariants' ? TVDefaultVariants<T[P]['variants'], T[P]['slots'], object, undefined>
|
||||
: never
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility type to flatten intersection types for better IDE hover information.
|
||||
* @template T The type to flatten.
|
||||
*/
|
||||
type Id<T> = {} & { [P in keyof T]: T[P] }
|
||||
|
||||
type ComponentVariants<T extends { variants?: Record<string, Record<string, any>> }> = {
|
||||
[K in keyof T['variants']]: keyof T['variants'][K]
|
||||
}
|
||||
|
||||
type ComponentSlots<T extends { slots?: Record<string, any> }> = Id<{
|
||||
[K in keyof T['slots']]?: ClassValue
|
||||
}>
|
||||
|
||||
type GetComponentAppConfig<A, U extends string, K extends string> =
|
||||
A extends Record<U, Record<K, any>> ? A[U][K] : {}
|
||||
|
||||
type ComponentAppConfig<
|
||||
T,
|
||||
A extends Record<string, any>,
|
||||
K extends string,
|
||||
U extends string = 'ui' | 'uiPro' | 'uiPro.prose'
|
||||
> = A & (
|
||||
U extends 'uiPro.prose'
|
||||
? { uiPro?: { prose?: { [k in K]?: Partial<T> } } }
|
||||
: { [key in Exclude<U, 'uiPro.prose'>]?: { [k in K]?: Partial<T> } }
|
||||
)
|
||||
|
||||
/**
|
||||
* Defines the configuration shape expected for a component.
|
||||
* @template T The component's theme imported from `#build/ui/*`.
|
||||
* @template A The base AppConfig type from `@nuxt/schema`.
|
||||
* @template K The key identifying the component (e.g., 'badge').
|
||||
* @template U The top-level key in AppConfig ('ui' or 'uiPro').
|
||||
*/
|
||||
export type ComponentConfig<
|
||||
T extends Record<string, any>,
|
||||
A extends Record<string, any>,
|
||||
K extends string,
|
||||
U extends 'ui' | 'uiPro' | 'uiPro.prose' = 'ui'
|
||||
> = {
|
||||
AppConfig: ComponentAppConfig<T, A, K, U>
|
||||
variants: ComponentVariants<T & GetComponentAppConfig<A, U, K>>
|
||||
slots: ComponentSlots<T>
|
||||
}
|
||||
@@ -1,20 +1,5 @@
|
||||
import type { AcceptableValue as _AcceptableValue } from 'reka-ui'
|
||||
import type { ClassValue } from 'tailwind-variants'
|
||||
import type { VNode } from 'vue'
|
||||
|
||||
export interface TightMap<O = any> {
|
||||
[key: string]: TightMap | O
|
||||
}
|
||||
|
||||
export type DeepPartial<T, O = any> = {
|
||||
[P in keyof T]?: T[P] extends Array<string>
|
||||
? string
|
||||
: T[P] extends object
|
||||
? DeepPartial<T[P], O>
|
||||
: T[P];
|
||||
} & {
|
||||
[key: string]: O | TightMap<O>
|
||||
}
|
||||
import type { AcceptableValue as _AcceptableValue } from 'reka-ui'
|
||||
|
||||
export type DynamicSlotsKeys<Name extends string | undefined, Suffix extends string | undefined = undefined> = (
|
||||
Name extends string
|
||||
@@ -56,13 +41,13 @@ export type MergeTypes<T extends object> = {
|
||||
export type GetItemKeys<I> = keyof Extract<NestedItem<I>, object>
|
||||
|
||||
export type GetItemValue<I, VK extends GetItemKeys<I> | undefined, T extends NestedItem<I> = NestedItem<I>> =
|
||||
T extends object
|
||||
? VK extends undefined
|
||||
? T
|
||||
: VK extends keyof T
|
||||
? T[VK]
|
||||
: never
|
||||
: T
|
||||
T extends object
|
||||
? VK extends undefined
|
||||
? T
|
||||
: VK extends keyof T
|
||||
? T[VK]
|
||||
: never
|
||||
: T
|
||||
|
||||
export type GetModelValue<
|
||||
T,
|
||||
@@ -92,48 +77,4 @@ export type EmitsToProps<T> = {
|
||||
: never
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility type to flatten intersection types for better IDE hover information.
|
||||
* @template T The type to flatten.
|
||||
*/
|
||||
type Id<T> = {} & { [P in keyof T]: T[P] }
|
||||
|
||||
type ComponentVariants<T extends { variants?: Record<string, Record<string, any>> }> = {
|
||||
[K in keyof T['variants']]: keyof T['variants'][K]
|
||||
}
|
||||
|
||||
type ComponentSlots<T extends { slots?: Record<string, any> }> = Id<{
|
||||
[K in keyof T['slots']]?: ClassValue
|
||||
}>
|
||||
|
||||
type GetComponentAppConfig<A, U extends string, K extends string> =
|
||||
A extends Record<U, Record<K, any>> ? A[U][K] : {}
|
||||
|
||||
type ComponentAppConfig<
|
||||
T,
|
||||
A extends Record<string, any>,
|
||||
K extends string,
|
||||
U extends string = 'ui' | 'uiPro' | 'uiPro.prose'
|
||||
> = A & (
|
||||
U extends 'uiPro.prose'
|
||||
? { uiPro?: { prose?: { [k in K]?: Partial<T> } } }
|
||||
: { [key in Exclude<U, 'uiPro.prose'>]?: { [k in K]?: Partial<T> } }
|
||||
)
|
||||
|
||||
/**
|
||||
* Defines the configuration shape expected for a component.
|
||||
* @template T The component's theme imported from `#build/ui/*`.
|
||||
* @template A The base AppConfig type from `@nuxt/schema`.
|
||||
* @template K The key identifying the component (e.g., 'badge').
|
||||
* @template U The top-level key in AppConfig ('ui' or 'uiPro').
|
||||
*/
|
||||
export type ComponentConfig<
|
||||
T extends Record<string, any>,
|
||||
A extends Record<string, any>,
|
||||
K extends string,
|
||||
U extends 'ui' | 'uiPro' | 'uiPro.prose' = 'ui'
|
||||
> = {
|
||||
AppConfig: ComponentAppConfig<T, A, K, U>
|
||||
variants: ComponentVariants<T & GetComponentAppConfig<A, U, K>>
|
||||
slots: ComponentSlots<T>
|
||||
}
|
||||
export * from './tv'
|
||||
|
||||
34
src/runtime/utils/colors.ts
Normal file
34
src/runtime/utils/colors.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import colors from 'tailwindcss/colors'
|
||||
|
||||
export const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const
|
||||
|
||||
export function getColor(color: keyof typeof colors, shade: typeof shades[number]): string {
|
||||
if (color in colors && typeof colors[color] === 'object' && shade in colors[color]) {
|
||||
return colors[color][shade] as string
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export function generateShades(key: string, value: string) {
|
||||
return `${shades.map(shade => `--ui-color-${key}-${shade}: var(--color-${value === 'neutral' ? 'old-neutral' : value}-${shade}, ${getColor(value as keyof typeof colors, shade)});`).join('\n ')}`
|
||||
}
|
||||
|
||||
export function generateColor(key: string, shade: number) {
|
||||
return `--ui-${key}: var(--ui-color-${key}-${shade});`
|
||||
}
|
||||
|
||||
export function generateColorStyles(colors: Record<string, string>) {
|
||||
const { neutral, ...rest } = colors
|
||||
|
||||
return `@layer base {
|
||||
:root {
|
||||
${Object.entries(colors).map(([key, value]: [string, string]) => generateShades(key, value)).join('\n ')}
|
||||
}
|
||||
:root, .light {
|
||||
${Object.keys(rest).map(key => generateColor(key, 500)).join('\n ')}
|
||||
}
|
||||
.dark {
|
||||
${Object.keys(rest).map(key => generateColor(key, 400)).join('\n ')}
|
||||
}
|
||||
}`
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import { reactive } from 'vue'
|
||||
import appConfig from '#build/app.config'
|
||||
|
||||
export const useAppConfig = () => appConfig
|
||||
const _appConfig = reactive(appConfig)
|
||||
|
||||
export const useAppConfig = () => _appConfig
|
||||
|
||||
35
src/runtime/vue/plugins/colors.ts
Normal file
35
src/runtime/vue/plugins/colors.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { computed, watchEffect } from 'vue'
|
||||
import { useHead } from '@unhead/vue'
|
||||
import type { Plugin } from 'vue'
|
||||
import { useAppConfig } from '../composables/useAppConfig'
|
||||
import { generateColorStyles } from '../../utils/colors'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
app.runWithContext(() => {
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const root = computed(() => generateColorStyles(appConfig.ui.colors))
|
||||
|
||||
useHead({
|
||||
style: [{
|
||||
innerHTML: root,
|
||||
tagPriority: -2,
|
||||
id: 'nuxt-ui-colors'
|
||||
}]
|
||||
})
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
watchEffect(() => {
|
||||
let styleEl = document.querySelector('#nuxt-ui-colors-vue') as HTMLStyleElement
|
||||
if (!styleEl) {
|
||||
styleEl = document.createElement('style')
|
||||
styleEl.id = 'nuxt-ui-colors-vue'
|
||||
document.head.appendChild(styleEl)
|
||||
}
|
||||
styleEl.innerHTML = root.value
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
} satisfies Plugin
|
||||
@@ -44,15 +44,14 @@ export function getTemplates(options: ModuleOptions, uiConfig: Record<string, an
|
||||
}
|
||||
|
||||
function generateVariantDeclarations(variants: string[]) {
|
||||
return variants.map((variant) => {
|
||||
return variants.filter(variant => json.includes(`as typeof ${variant}`)).map((variant) => {
|
||||
const keys = Object.keys(result.variants[variant])
|
||||
return `const ${variant} = ${JSON.stringify(keys, null, 2)} as const`
|
||||
})
|
||||
}
|
||||
|
||||
// For local development, import directly from theme
|
||||
const isUiDev = true
|
||||
if (isUiDev) {
|
||||
if (process.argv.includes('--uiDev')) {
|
||||
const templatePath = fileURLToPath(new URL(`./theme/${kebabCase(component)}`, import.meta.url))
|
||||
return [
|
||||
`import template from ${JSON.stringify(templatePath)}`,
|
||||
@@ -150,7 +149,7 @@ export function getTemplates(options: ModuleOptions, uiConfig: Record<string, an
|
||||
templates.push({
|
||||
filename: 'types/ui.d.ts',
|
||||
getContents: () => `import * as ui from '#build/ui'
|
||||
import type { DeepPartial } from '@nuxt/ui'
|
||||
import type { TVConfig } from '@nuxt/ui'
|
||||
import type { defaultConfig } from 'tailwind-variants'
|
||||
import colors from 'tailwindcss/colors'
|
||||
|
||||
@@ -166,7 +165,7 @@ type AppConfigUI = {
|
||||
}
|
||||
icons?: Partial<typeof icons>
|
||||
tv?: typeof defaultConfig
|
||||
} & DeepPartial<typeof ui>
|
||||
} & TVConfig<typeof ui>
|
||||
|
||||
declare module '@nuxt/schema' {
|
||||
interface AppConfigInput {
|
||||
|
||||
@@ -7,7 +7,7 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
|
||||
heading: 'text-center font-medium truncate mx-auto',
|
||||
grid: 'w-full border-collapse select-none space-y-1 focus:outline-none',
|
||||
gridRow: 'grid grid-cols-7',
|
||||
gridRow: 'grid grid-cols-7 place-items-center',
|
||||
gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
|
||||
gridBody: 'grid',
|
||||
headCell: 'rounded-md',
|
||||
@@ -22,7 +22,7 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
}])),
|
||||
neutral: {
|
||||
headCell: 'text-highlighted',
|
||||
cellTrigger: 'focus-visible:ring-inverted data-[selected]:bg-inverted data-today:not-data-[selected]:text-inverted data-[highlighted]:bg-inverted/20 hover:not-data-[selected]:bg-inverted/10'
|
||||
cellTrigger: 'focus-visible:ring-inverted data-[selected]:bg-inverted data-today:not-data-[selected]:text-highlighted data-[highlighted]:bg-inverted/20 hover:not-data-[selected]:bg-inverted/10'
|
||||
}
|
||||
},
|
||||
size: {
|
||||
|
||||
@@ -2,10 +2,10 @@ export default {
|
||||
slots: {
|
||||
root: 'data-[disabled]:opacity-75',
|
||||
picker: 'flex gap-4',
|
||||
selector: 'rounded-md',
|
||||
selector: 'rounded-md touch-none',
|
||||
selectorBackground: 'w-full h-full relative rounded-md',
|
||||
selectorThumb: '-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed',
|
||||
track: 'w-[8px] relative rounded-md',
|
||||
track: 'w-[8px] relative rounded-md touch-none',
|
||||
trackThumb: 'absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed'
|
||||
},
|
||||
variants: {
|
||||
|
||||
@@ -27,7 +27,7 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
separator: 'px-2 h-px bg-border',
|
||||
viewportWrapper: 'absolute top-full left-0 flex w-full',
|
||||
viewport: 'relative overflow-hidden bg-default shadow-lg rounded-md ring ring-default h-(--reka-navigation-menu-viewport-height) w-full transition-[width,height,left] duration-200 origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] z-[1]',
|
||||
content: 'absolute top-0 left-0 w-full sm:w-auto',
|
||||
content: 'absolute top-0 left-0 w-full',
|
||||
indicator: 'absolute data-[state=visible]:animate-[fade-in_100ms_ease-out] data-[state=hidden]:animate-[fade-out_100ms_ease-in] data-[state=hidden]:opacity-0 bottom-0 z-[2] w-(--reka-navigation-menu-indicator-size) translate-x-(--reka-navigation-menu-indicator-position) flex h-2.5 items-end justify-center overflow-hidden transition-[translate,width] duration-200',
|
||||
arrow: 'relative top-[50%] size-2.5 rotate-45 border border-default bg-default z-[1] rounded-xs'
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
root: 'flex items-center gap-2',
|
||||
list: 'relative flex p-1 group',
|
||||
indicator: 'absolute transition-[translate,width] duration-200',
|
||||
trigger: ['group relative inline-flex items-center shrink-0 min-w-0 data-[state=inactive]:text-muted hover:data-[state=inactive]:not-disabled:text-default font-medium rounded-md disabled:cursor-not-allowed disabled:opacity-75', options.theme.transitions && 'transition-colors'],
|
||||
trigger: ['group relative inline-flex items-center min-w-0 data-[state=inactive]:text-muted hover:data-[state=inactive]:not-disabled:text-default font-medium rounded-md disabled:cursor-not-allowed disabled:opacity-75', options.theme.transitions && 'transition-colors'],
|
||||
content: 'focus:outline-none w-full',
|
||||
leadingIcon: 'shrink-0',
|
||||
leadingAvatar: 'shrink-0',
|
||||
@@ -20,12 +20,13 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
variant: {
|
||||
pill: {
|
||||
list: 'bg-elevated rounded-lg',
|
||||
trigger: 'flex-1 w-full',
|
||||
trigger: 'grow',
|
||||
indicator: 'rounded-md shadow-xs'
|
||||
},
|
||||
link: {
|
||||
list: 'border-default',
|
||||
indicator: 'rounded-full'
|
||||
indicator: 'rounded-full',
|
||||
trigger: 'focus:outline-none'
|
||||
}
|
||||
},
|
||||
orientation: {
|
||||
|
||||
@@ -20,10 +20,10 @@ import PluginsPlugin from './plugins/plugins'
|
||||
import AppConfigPlugin from './plugins/app-config'
|
||||
import ComponentImportPlugin from './plugins/components'
|
||||
import NuxtEnvironmentPlugin from './plugins/nuxt-environment'
|
||||
|
||||
import type { DeepPartial } from './runtime/types/utils'
|
||||
import AutoImportPlugin from './plugins/auto-import'
|
||||
|
||||
import type { TVConfig } from './runtime/types/tv'
|
||||
|
||||
type NeutralColor = 'slate' | 'gray' | 'zinc' | 'neutral' | 'stone'
|
||||
type Color = Exclude<keyof typeof colors, 'inherit' | 'current' | 'transparent' | 'black' | 'white' | NeutralColor> | (string & {})
|
||||
|
||||
@@ -31,7 +31,7 @@ type AppConfigUI = {
|
||||
// TODO: add type hinting for colors from `options.theme.colors`
|
||||
colors?: Record<string, Color> & { neutral?: NeutralColor }
|
||||
icons?: Partial<typeof icons>
|
||||
} & DeepPartial<typeof ui>
|
||||
} & TVConfig<typeof ui>
|
||||
|
||||
export interface NuxtUIOptions extends Omit<ModuleOptions, 'fonts' | 'colorMode'> {
|
||||
/** Whether to generate declaration files for auto-imported components. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,12 +3,12 @@
|
||||
exports[`ColorPicker > renders with as correctly 1`] = `
|
||||
"<section data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,12 +18,12 @@ exports[`ColorPicker > renders with as correctly 1`] = `
|
||||
exports[`ColorPicker > renders with class correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75 w-96">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,12 +33,12 @@ exports[`ColorPicker > renders with class correctly 1`] = `
|
||||
exports[`ColorPicker > renders with disabled correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75" data-disabled="true">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;" data-disabled="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;" data-disabled="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,12 +48,12 @@ exports[`ColorPicker > renders with disabled correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format cmyk correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.310000000000002%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48666666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,12 +63,12 @@ exports[`ColorPicker > renders with format cmyk correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format hex correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.313726000000003%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48704666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,12 +78,12 @@ exports[`ColorPicker > renders with format hex correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format hsl correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.400000000000006%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.5%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,12 +93,12 @@ exports[`ColorPicker > renders with format hsl correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format lab correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #00FF6F;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF6F;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C757; left: 100%; top: 22.031043999999994%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF6F; top: 40.609066111111105%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,12 +108,12 @@ exports[`ColorPicker > renders with format lab correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format rgb correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.313726000000003%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48704666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -123,12 +123,12 @@ exports[`ColorPicker > renders with format rgb correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size lg correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-44 h-44" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-44 h-44" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-44" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-44" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,12 +138,12 @@ exports[`ColorPicker > renders with size lg correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size md correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,12 +153,12 @@ exports[`ColorPicker > renders with size md correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size sm correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-40 h-40" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-40 h-40" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-40" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-40" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,12 +168,12 @@ exports[`ColorPicker > renders with size sm correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size xl correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-46 h-46" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-46 h-46" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-46" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-46" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -183,12 +183,12 @@ exports[`ColorPicker > renders with size xl correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size xs correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-4">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-38 h-38" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-38 h-38" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-38" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-38" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,12 +198,12 @@ exports[`ColorPicker > renders with size xs correctly 1`] = `
|
||||
exports[`ColorPicker > renders with ui correctly 1`] = `
|
||||
"<div data-v-c9a043d6="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-c9a043d6="" class="flex gap-8">
|
||||
<div data-v-c9a043d6="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-c9a043d6="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-c9a043d6="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-c9a043d6="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
exports[`ColorPicker > renders with as correctly 1`] = `
|
||||
"<section data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,12 +18,12 @@ exports[`ColorPicker > renders with as correctly 1`] = `
|
||||
exports[`ColorPicker > renders with class correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75 w-96">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,12 +33,12 @@ exports[`ColorPicker > renders with class correctly 1`] = `
|
||||
exports[`ColorPicker > renders with disabled correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75" data-disabled="true">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;" data-disabled="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;" data-disabled="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,12 +48,12 @@ exports[`ColorPicker > renders with disabled correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format cmyk correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.310000000000002%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48666666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,12 +63,12 @@ exports[`ColorPicker > renders with format cmyk correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format hex correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.313726000000003%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48704666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,12 +78,12 @@ exports[`ColorPicker > renders with format hex correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format hsl correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.400000000000006%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.5%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,12 +93,12 @@ exports[`ColorPicker > renders with format hsl correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format lab correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #00FF6F;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF6F;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C757; left: 100%; top: 22.031043999999994%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF6F; top: 40.609066111111105%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,12 +108,12 @@ exports[`ColorPicker > renders with format lab correctly 1`] = `
|
||||
exports[`ColorPicker > renders with format rgb correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #00FF8C;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00C16A; left: 100%; top: 24.313726000000003%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #00FF8C; top: 42.48704666666667%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -123,12 +123,12 @@ exports[`ColorPicker > renders with format rgb correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size lg correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-44 h-44" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-44 h-44" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-44" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-44" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,12 +138,12 @@ exports[`ColorPicker > renders with size lg correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size md correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,12 +153,12 @@ exports[`ColorPicker > renders with size md correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size sm correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-40 h-40" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-40 h-40" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-40" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-40" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,12 +168,12 @@ exports[`ColorPicker > renders with size sm correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size xl correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-46 h-46" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-46 h-46" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-46" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-46" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -183,12 +183,12 @@ exports[`ColorPicker > renders with size xl correctly 1`] = `
|
||||
exports[`ColorPicker > renders with size xs correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-4">
|
||||
<div data-v-d6f23756="" class="rounded-md w-38 h-38" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-38 h-38" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-38" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-38" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,12 +198,12 @@ exports[`ColorPicker > renders with size xs correctly 1`] = `
|
||||
exports[`ColorPicker > renders with ui correctly 1`] = `
|
||||
"<div data-v-d6f23756="" class="data-[disabled]:opacity-75">
|
||||
<div data-v-d6f23756="" class="flex gap-8">
|
||||
<div data-v-d6f23756="" class="rounded-md w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="rounded-md touch-none w-42 h-42" style="background-color: #FF0000;">
|
||||
<div data-v-d6f23756="" class="w-full h-full relative rounded-md" data-color-picker-background="">
|
||||
<div data-v-d6f23756="" class="-translate-y-1/2 -translate-x-1/2 absolute size-4 ring-2 ring-(--color-white) rounded-full cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FFFFFF; left: 0%; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="w-[8px] relative rounded-md touch-none h-42" data-color-picker-track="">
|
||||
<div data-v-d6f23756="" class="absolute transform -translate-y-1/2 -translate-x-[4px] rtl:translate-x-[4px] size-4 rounded-full ring-2 ring-(--color-white) cursor-pointer data-[disabled]:cursor-not-allowed" style="background-color: #FF0000; top: 0%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -842,17 +842,23 @@ exports[`NavigationMenu > renders with orientation vertical and collapsed correc
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
<li data-menu-item="" class="min-w-0"><button type="button" class="group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary flex-row py-1.5 before:inset-y-px before:inset-x-0 text-muted hover:text-highlighted hover:before:bg-elevated/50 transition-colors before:transition-colors px-1.5" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="shrink-0 size-5 text-dimmed group-hover:text-default transition-colors" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<li data-state="closed" class="min-w-0" value="1"><button type="button" aria-controls="" aria-expanded="false" data-state="closed" class="group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary flex-row py-1.5 before:inset-y-px before:inset-x-0 text-muted hover:text-highlighted hover:before:bg-elevated/50 transition-colors before:transition-colors px-1.5" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="shrink-0 size-5 text-dimmed group-hover:text-default transition-colors" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</button>
|
||||
<!--v-if-->
|
||||
<div class="data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] overflow-hidden" id="reka-collapsible-content-v-1" hidden="" data-state="closed" style="--reka-collapsible-content-height: 0px; --reka-collapsible-content-width: 0px;">
|
||||
<!---->
|
||||
</div>
|
||||
</li>
|
||||
<li data-menu-item="" class="min-w-0"><button type="button" class="group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary flex-row py-1.5 before:inset-y-px before:inset-x-0 text-primary before:bg-elevated px-1.5" data-active="" aria-current="page" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="shrink-0 size-5 text-primary group-data-[state=open]:text-primary" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<li data-state="closed" class="min-w-0" value="2"><button type="button" aria-controls="" aria-expanded="false" data-state="closed" class="group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary flex-row py-1.5 before:inset-y-px before:inset-x-0 text-primary before:bg-elevated px-1.5" data-active="" aria-current="page" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="shrink-0 size-5 text-primary group-data-[state=open]:text-primary" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</button>
|
||||
<!--v-if-->
|
||||
<div class="data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] overflow-hidden" id="reka-collapsible-content-v-2" hidden="" data-state="closed" style="--reka-collapsible-content-height: 0px; --reka-collapsible-content-width: 0px;">
|
||||
<!---->
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1226,7 +1232,7 @@ exports[`NavigationMenu > renders with unmountOnHide correctly 1`] = `
|
||||
<div class="absolute top-full left-0 flex w-full justify-center">
|
||||
<!--v-if-->
|
||||
<div class="relative overflow-hidden bg-default shadow-lg rounded-md ring ring-default h-(--reka-navigation-menu-viewport-height) w-full transition-[width,height,left] duration-200 origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] z-[1]" data-state="closed" data-orientation="horizontal" style="pointer-events: none;" hidden="">
|
||||
<div data-dismissable-layer="" style="pointer-events: none;" id="reka-navigation-menu-v-0-content-1" aria-labelledby="reka-navigation-menu-v-0-trigger-1" data-state="closed" data-orientation="horizontal" class="absolute top-0 left-0 w-full sm:w-auto data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]" hidden="">
|
||||
<div data-dismissable-layer="" style="pointer-events: none;" id="reka-navigation-menu-v-0-content-1" aria-labelledby="reka-navigation-menu-v-0-trigger-1" data-state="closed" data-orientation="horizontal" class="absolute top-0 left-0 w-full data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]" hidden="">
|
||||
<ul class="grid p-2 grid-cols-2 gap-2">
|
||||
<li class=""><button type="button" class="group size-full px-3 py-2 rounded-md flex items-start gap-2 text-start focus-visible:outline-primary hover:bg-elevated/50 text-default hover:text-highlighted transition-colors" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="size-5 shrink-0 text-dimmed group-hover:text-default transition-colors" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<div class="flex flex-col items-start">
|
||||
@@ -1262,7 +1268,7 @@ exports[`NavigationMenu > renders with unmountOnHide correctly 1`] = `
|
||||
</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div data-dismissable-layer="" style="pointer-events: none;" id="reka-navigation-menu-v-0-content-2" aria-labelledby="reka-navigation-menu-v-0-trigger-2" data-state="closed" data-orientation="horizontal" class="absolute top-0 left-0 w-full sm:w-auto data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]" hidden="">
|
||||
<div data-dismissable-layer="" style="pointer-events: none;" id="reka-navigation-menu-v-0-content-2" aria-labelledby="reka-navigation-menu-v-0-trigger-2" data-state="closed" data-orientation="horizontal" class="absolute top-0 left-0 w-full data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]" hidden="">
|
||||
<ul class="grid p-2 grid-cols-2 gap-2">
|
||||
<li class=""><a href="/components/link" class="group size-full px-3 py-2 rounded-md flex items-start gap-2 text-start focus-visible:outline-primary hover:bg-elevated/50 text-default hover:text-highlighted transition-colors" data-reka-collection-item=""><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="size-5 shrink-0 text-dimmed group-hover:text-default transition-colors" width="1em" height="1em" viewBox="0 0 16 16"></svg>
|
||||
<div class="flex flex-col items-start">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user