Compare commits

..

26 Commits

Author SHA1 Message Date
Romain Hamel
75a0ac84c9 fix(Form): extend Form<...> type with HTMLFormElement 2024-04-07 13:09:55 +02:00
Eugen Istoc
07a4d13c0f fix(Slideover): wait for transition to complete to reset state (#1624) 2024-04-05 19:31:29 +02:00
renovate[bot]
9e90d1768b chore(deps): update devdependency @nuxt/eslint-config to ^0.3.0 (#1623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 17:51:40 +02:00
Neil Richter
91e5002050 feat(Accordion): add unmount prop to allow lazy mounting for heavy components (#1590) 2024-04-05 14:11:31 +02:00
renovate[bot]
eb68d0d453 chore(deps): update devdependency @nuxt/ui-pro to v1.1.0-28538540.a353e68 (#1622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 14:08:08 +02:00
Neil Richter
2bdb5d2b42 fix(Modal): wait for transition to complete to reset state (#1618) 2024-04-05 14:07:51 +02:00
renovate[bot]
b62cd7905d chore(deps): update devdependency @nuxt/ui-pro to v1.1.0-28538504.d4106a4 (#1620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 12:44:03 +02:00
Eugen Istoc
58faa1053b fix(Slideover): remove dynamic component when closing (#1615)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-04-05 12:43:50 +02:00
Kshitij Subedi
e909884d03 fix(Carousel): next and prev buttons disabled (#1619) 2024-04-05 12:20:50 +02:00
renovate[bot]
5e84fd0570 chore(deps): update devdependency @nuxtjs/plausible to v1 (#1610)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 12:18:39 +02:00
Benjamin Canac
98c0f567fc docs: replace i-heroicons-credit-card with i-heroicons-ticket 2024-04-05 11:57:47 +02:00
renovate[bot]
379d20fc3c chore(deps): update all non-major dependencies (#1602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 11:28:22 +02:00
renovate[bot]
c12f94653e chore(deps): update nuxt framework to ^3.11.2 (#1613)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-05 11:06:04 +02:00
vahid bagheri
2392b4aa40 fix(Popover/Dropdown): prevent unintended closure on touchstart in mobile devices (#1609) 2024-04-04 00:18:40 +02:00
Benjamin Canac
36055ba978 chore(release): v2.15.1 2024-04-02 13:08:11 +02:00
renovate[bot]
73541f2d4f chore(deps): update all non-major dependencies (#1562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-02 12:02:39 +02:00
Benjamin Canac
03030ab1db docs(nuxt.config): remove @nuxtjs/google-fonts and @nuxtjs/fontaine config 2024-03-29 10:57:31 +01:00
Cardona Simon
c98d6e31c0 fix(Checkbox): @change event value (#1580)
Co-authored-by: Romain Hamel <rom.hml@gmail.com>
2024-03-28 21:29:29 +01:00
Benjamin Canac
49b73aa024 feat(Avatar): add as prop to use NuxtImg underneath
Resolves #1577
2024-03-28 11:04:20 +01:00
Mahdi Shah Abbasian
bd8b737642 fix(Divider): add w-full only on horizontal wrapper (#1565) 2024-03-27 13:57:09 +01:00
Neil Richter
dd8a122933 docs(installation): update regex to match @nuxt/eslint rules (#1572) 2024-03-27 13:55:23 +01:00
Qin Guan
0b799e4300 docs(icon): add link to theming icons section (#1571)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-03-27 13:54:38 +01:00
Benjamin Canac
8517897c34 fix(Popover): missing mouseenter event on container
Resolves #1564
2024-03-27 12:04:49 +01:00
Benjamin Canac
72889535e7 fix(Dropdown): missing mouseenter event on container 2024-03-27 12:04:31 +01:00
Romain Hamel
878f7078a2 fix(Input/SelectMenu): handle file type and change events (#1570) 2024-03-27 11:57:31 +01:00
Benjamin Canac
bd8118c124 docs(deps): update @nuxt/ui-pro 2024-03-26 14:18:21 +01:00
26 changed files with 1785 additions and 1047 deletions

View File

@@ -1,5 +1,21 @@
# Changelog
## [2.15.1](https://github.com/nuxt/ui/compare/v2.15.0...v2.15.1) (2024-04-02)
### Features
* **Avatar:** add `as` prop to use `NuxtImg` underneath ([49b73aa](https://github.com/nuxt/ui/commit/49b73aa024be14a9aa150a2804f4dcb18542fa49)), closes [#1577](https://github.com/nuxt/ui/issues/1577)
### Bug Fixes
* **Checkbox:** `[@change](https://github.com/change)` event value ([#1580](https://github.com/nuxt/ui/issues/1580)) ([c98d6e3](https://github.com/nuxt/ui/commit/c98d6e31c0e3f46b97957d5cf3de7f9da1f70c58))
* **Divider:** add `w-full` only on horizontal wrapper ([#1565](https://github.com/nuxt/ui/issues/1565)) ([bd8b737](https://github.com/nuxt/ui/commit/bd8b737642280e6a83b67f9a27dd7a823a77e963))
* **Dropdown:** missing `mouseenter` event on container ([7288953](https://github.com/nuxt/ui/commit/72889535e7e9763e7ebf59498f22c39bf09d6477))
* **Input/SelectMenu:** handle `file` type and `change` events ([#1570](https://github.com/nuxt/ui/issues/1570)) ([878f707](https://github.com/nuxt/ui/commit/878f7078a28c5e70a662682d1293db466d518c7d))
* **Popover:** missing `mouseenter` event on container ([8517897](https://github.com/nuxt/ui/commit/8517897c34adaa9e3624f867b43106deb59fcbe8)), closes [#1564](https://github.com/nuxt/ui/issues/1564)
## [2.15.0](https://github.com/nuxt/ui/compare/v2.14.2...v2.15.0) (2024-03-26)

View File

@@ -72,7 +72,7 @@ const links = computed(() => {
active: route.path.startsWith('/pro/getting-started') || route.path.startsWith('/pro/components') || route.path.startsWith('/pro/prose')
}, {
label: 'Pricing',
icon: 'i-heroicons-credit-card',
icon: 'i-heroicons-ticket',
to: '/pro/pricing'
}, {
label: 'Templates',

View File

@@ -194,7 +194,7 @@ To enable these two features, you can add the following to your `.vscode/setting
{
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "[\"'`]([^\"'`]*).*?[\"'`]"],
["/\\*ui\\*/\\s*{([^;]*)}", ":\\s*[\"'`]([^\"'`]*).*?[\"'`]"]
["/\\*\\s?ui\\s?\\*/\\s*{([^;]*)}", ":\\s*[\"'`]([^\"'`]*).*?[\"'`]"]
]
}
```
@@ -207,7 +207,7 @@ An example SFC using IntelliSense (note the `/*ui*/` prefix, also works with `re
</template>
<script setup lang="ts">
const ui = /*ui*/ {
const ui = /* ui */ {
background: 'bg-white dark:bg-slate-900'
}
</script>

View File

@@ -18,7 +18,11 @@ props:
::
::callout{icon="i-heroicons-exclamation-triangle"}
You won't be able to use any icon in the `name` prop here as icons are bundled using [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons), read more about this in [Theming](/getting-started/theming#icons).
You won't be able to use all icons in the `name` prop here as icons are bundled using [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons).
::
::callout{icon="i-heroicons-light-bulb"}
Don't forget to install and specify the icon collections you need in your `nuxt.config.ts`, read more about this in [Theming](/getting-started/theming#icons).
::
### Dynamic

View File

@@ -79,7 +79,7 @@ const links = computed(() => {
active: route.path.startsWith('/pro/getting-started') || route.path.startsWith('/pro/components') || route.path.startsWith('/pro/prose')
}, {
label: 'Pricing',
icon: 'i-heroicons-credit-card',
icon: 'i-heroicons-ticket',
to: '/pro/pricing'
}, {
label: 'Templates',

View File

@@ -74,16 +74,6 @@ export default defineNuxtConfig({
image: {
provider: 'ipx'
},
fontMetrics: {
fonts: ['DM Sans']
},
googleFonts: {
display: 'swap',
download: true,
families: {
'DM+Sans': [400, 500, 600, 700]
}
},
nitro: {
prerender: {
routes: [

View File

@@ -7,25 +7,24 @@
},
"devDependencies": {
"@iconify-json/heroicons": "^1.1.20",
"@iconify-json/simple-icons": "^1.1.97",
"@iconify-json/simple-icons": "^1.1.98",
"@nuxt/content": "^2.12.1",
"@nuxt/devtools": "^1.1.3",
"@nuxt/eslint-config": "^0.2.0",
"@nuxt/fonts": "^0.5.1",
"@nuxt/image": "^1.4.0",
"@nuxt/ui-pro": "npm:@nuxt/ui-pro-edge@1.0.2-28522949.b7de784",
"@nuxtjs/plausible": "^0.2.4",
"@octokit/rest": "^20.0.2",
"@nuxt/eslint-config": "^0.3.0",
"@nuxt/fonts": "^0.6.1",
"@nuxt/image": "^1.5.0",
"@nuxt/ui-pro": "npm:@nuxt/ui-pro-edge@1.1.0-28538540.a353e68",
"@nuxtjs/plausible": "^1.0.0",
"@octokit/rest": "^20.1.0",
"@vueuse/nuxt": "^10.9.0",
"date-fns": "^3.6.0",
"eslint": "^8.57.0",
"joi": "^17.12.2",
"nuxt": "^3.11.1",
"joi": "^17.12.3",
"nuxt": "^3.11.2",
"nuxt-cloudflare-analytics": "^1.0.8",
"nuxt-component-meta": "^0.6.3",
"nuxt-og-image": "^2.2.4",
"prettier": "^3.2.5",
"typescript": "^5.4.3",
"typescript": "^5.4.4",
"ufo": "^1.5.3",
"v-calendar": "^3.1.2",
"valibot": "^0.30.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@nuxt/ui",
"version": "2.15.0",
"version": "2.15.1",
"repository": "nuxt/ui",
"homepage": "https://ui.nuxt.com",
"type": "module",
@@ -37,14 +37,14 @@
"@headlessui/tailwindcss": "^0.2.0",
"@headlessui/vue": "^1.7.19",
"@iconify-json/heroicons": "^1.1.20",
"@nuxt/kit": "^3.11.1",
"@nuxt/kit": "^3.11.2",
"@nuxtjs/color-mode": "^3.3.3",
"@nuxtjs/tailwindcss": "^6.11.4",
"@popperjs/core": "^2.11.8",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@tailwindcss/typography": "^0.5.12",
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"@vueuse/math": "^10.9.0",
@@ -55,32 +55,32 @@
"pathe": "^1.1.2",
"scule": "^1.3.0",
"tailwind-merge": "^2.2.2",
"tailwindcss": "^3.4.1"
"tailwindcss": "^3.4.3"
},
"devDependencies": {
"@nuxt/eslint-config": "^0.2.0",
"@nuxt/eslint-config": "^0.3.0",
"@nuxt/module-builder": "^0.5.5",
"@nuxt/test-utils": "^3.12.0",
"@release-it/conventional-changelog": "^8.0.1",
"@vue/test-utils": "^2.4.5",
"eslint": "^8.57.0",
"happy-dom": "^14.3.6",
"joi": "^17.12.2",
"nuxt": "^3.11.1",
"happy-dom": "^14.5.1",
"joi": "^17.12.3",
"nuxt": "^3.11.2",
"release-it": "^17.1.1",
"typescript": "^5.4.3",
"typescript": "^5.4.4",
"unbuild": "^2.0.0",
"valibot": "^0.30.0",
"vitest": "^1.4.0",
"vitest-environment-nuxt": "^1.0.0",
"vue-tsc": "^2.0.7",
"vue-tsc": "^2.0.10",
"yup": "^1.4.0",
"zod": "^3.22.4"
},
"resolutions": {
"@nuxt/kit": "^3.11.1",
"@nuxt/schema": "3.11.1",
"tailwindcss": "3.4.1",
"@nuxt/kit": "^3.11.2",
"@nuxt/schema": "3.11.2",
"tailwindcss": "^3.4.3",
"@headlessui/vue": "1.7.19",
"vue": "3.4.21"
}

2489
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -280,8 +280,8 @@ export default defineComponent({
})
}
function onChange (event: any) {
if (event.target.checked) {
function onChange (checked: boolean) {
if (checked) {
selectAllRows()
} else {
selected.value = []

View File

@@ -39,13 +39,27 @@
@before-leave="onBeforeLeave"
@leave="onLeave"
>
<div v-show="open">
<HDisclosurePanel :class="[ui.item.base, ui.item.size, ui.item.color, ui.item.padding]" static>
<slot :name="item.slot || 'item'" :item="item" :index="index" :open="open" :close="close">
{{ item.content }}
</slot>
</HDisclosurePanel>
</div>
<HDisclosurePanel
v-if="unmount"
:class="[ui.item.base, ui.item.size, ui.item.color, ui.item.padding]"
unmount
>
<slot :name="item.slot || 'item'" :item="item" :index="index" :open="open" :close="close">
{{ item.content }}
</slot>
</HDisclosurePanel>
<template v-else>
<div v-show="open">
<HDisclosurePanel
:class="[ui.item.base, ui.item.size, ui.item.color, ui.item.padding]"
static
>
<slot :name="item.slot || 'item'" :item="item" :index="index" :open="open" :close="close">
{{ item.content }}
</slot>
</HDisclosurePanel>
</div>
</template>
</Transition>
</HDisclosure>
</div>
@@ -91,6 +105,10 @@ export default defineComponent({
type: String,
default: () => config.default.openIcon
},
unmount: {
type: Boolean,
default: false
},
closeIcon: {
type: String,
default: () => config.default.closeIcon

View File

@@ -1,13 +1,14 @@
<template>
<span :class="wrapperClass">
<img
<component
:is="as"
v-if="url && !error"
:class="imgClass"
:alt="alt"
:src="url"
v-bind="attrs"
@error="onError"
>
/>
<span v-else-if="text" :class="ui.text">{{ text }}</span>
<UIcon v-else-if="icon" :name="icon" :class="iconClass" />
<span v-else-if="placeholder" :class="ui.placeholder">{{ placeholder }}</span>
@@ -39,6 +40,10 @@ export default defineComponent({
},
inheritAttrs: false,
props: {
as: {
type: [String, Object],
default: 'img'
},
src: {
type: [String, Boolean],
default: null

View File

@@ -56,7 +56,7 @@
</template>
<script lang="ts">
import { ref, toRef, toRefs, computed, defineComponent } from 'vue'
import { ref, toRef, computed, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { twMerge } from 'tailwind-merge'
import { mergeConfig } from '../../utils'
@@ -112,10 +112,9 @@ export default defineComponent({
const carouselRef = ref<HTMLElement>()
const itemWidth = ref(0)
const { x, arrivedState } = useScroll(carouselRef, { behavior: 'smooth' })
const { width: carouselWidth } = useElementSize(carouselRef)
const { x } = useScroll(carouselRef, { behavior: 'smooth' })
const { left: isFirst, right: isLast } = toRefs(arrivedState)
const { width: carouselWidth } = useElementSize(carouselRef)
useCarouselScroll(carouselRef)
@@ -125,7 +124,13 @@ export default defineComponent({
itemWidth.value = entry?.target?.firstElementChild?.clientWidth || 0
})
const currentPage = computed(() => Math.round(x.value / itemWidth.value) + 1)
const currentPage = computed(() => {
if (!itemWidth.value) {
return 0
}
return Math.round(x.value / itemWidth.value) + 1
})
const pages = computed(() => {
if (!itemWidth.value) {
@@ -135,6 +140,9 @@ export default defineComponent({
return props.items.length - Math.round(carouselWidth.value / itemWidth.value) + 1
})
const isFirst = computed(() => currentPage.value <= 1)
const isLast = computed(() => currentPage.value === pages.value)
function onClickNext () {
x.value += itemWidth.value
}

View File

@@ -17,7 +17,7 @@
</slot>
</HMenuButton>
<div v-if="open && items.length" ref="container" :class="[ui.container, ui.width]" :style="containerStyle">
<div v-if="open && items.length" ref="container" :class="[ui.container, ui.width]" :style="containerStyle" @mouseenter="onMouseEnter">
<Transition appear v-bind="ui.transition">
<div>
<div v-if="popper.arrow" data-popper-arrow :class="Object.values(ui.arrow)" />
@@ -182,8 +182,8 @@ export default defineComponent({
}
})
function onTouchStart () {
if (!menuApi.value) {
function onTouchStart (event: TouchEvent) {
if (!event.cancelable || !menuApi.value) {
return
}

View File

@@ -119,7 +119,7 @@ export default defineComponent({
})
const onChange = (event: Event) => {
emit('change', (event.target as HTMLInputElement).value)
emit('change', (event.target as HTMLInputElement).checked)
emitFormChange()
}

View File

@@ -205,16 +205,19 @@ export default defineComponent({
}
const onChange = (event: Event) => {
const value = (event.target as HTMLInputElement).value
emit('change', value)
if (modelModifiers.value.lazy) {
updateInput(value)
}
// Update trimmed input so that it has same behavior as native input https://github.com/vuejs/core/blob/5ea8a8a4fab4e19a71e123e4d27d051f5e927172/packages/runtime-dom/src/directives/vModel.ts#L63
if (modelModifiers.value.trim) {
(event.target as HTMLInputElement).value = value.trim()
if (props.type === 'file') {
const value = (event.target as HTMLInputElement).files
emit('change', value)
} else {
const value = (event.target as HTMLInputElement).value
emit('change', value)
if (modelModifiers.value.lazy) {
updateInput(value)
}
// Update trimmed input so that it has same behavior as native input https://github.com/vuejs/core/blob/5ea8a8a4fab4e19a71e123e4d27d051f5e927172/packages/runtime-dom/src/directives/vModel.ts#L63
if (modelModifiers.value.trim) {
(event.target as HTMLInputElement).value = value.trim()
}
}
}

View File

@@ -63,7 +63,7 @@
autofocus
autocomplete="off"
:class="uiMenu.input"
@change="onChange"
@change="onQueryChange"
/>
<component
:is="searchable ? 'HComboboxOption' : 'HListboxOption'"
@@ -505,14 +505,13 @@ export default defineComponent({
}
})
function onUpdate (event: any) {
emit('update:modelValue', event)
function onUpdate (value: any) {
emit('update:modelValue', value)
emit('change', value)
emitFormChange()
}
function onChange (event: any) {
emit('change', (event.target as HTMLInputElement).value)
emitFormChange()
function onQueryChange (event: any) {
query.value = event.target.value
}
@@ -547,7 +546,7 @@ export default defineComponent({
// eslint-disable-next-line vue/no-dupe-keys
query,
onUpdate,
onChange
onQueryChange
}
}
})

View File

@@ -1,5 +1,5 @@
<template>
<TransitionRoot :appear="appear" :show="isOpen" as="template">
<TransitionRoot :appear="appear" :show="isOpen" as="template" @after-leave="onAfterLeave">
<HDialog :class="ui.wrapper" v-bind="attrs" @close="close">
<TransitionChild v-if="overlay" as="template" :appear="appear" v-bind="ui.overlay.transition">
<div :class="[ui.overlay.base, ui.overlay.background]" />
@@ -82,7 +82,7 @@ export default defineComponent({
default: () => ({})
}
},
emits: ['update:modelValue', 'close', 'close-prevented'],
emits: ['update:modelValue', 'close', 'close-prevented', 'after-leave'],
setup (props, { emit }) {
const { ui, attrs } = useUI('modal', toRef(props, 'ui'), config, toRef(props, 'class'))
@@ -117,6 +117,10 @@ export default defineComponent({
emit('close')
}
const onAfterLeave = () => {
emit('after-leave')
}
provideUseId(() => useId())
return {
@@ -125,6 +129,7 @@ export default defineComponent({
attrs,
isOpen,
transitionClass,
onAfterLeave,
close
}
}

View File

@@ -1,5 +1,11 @@
<template>
<component :is="modalState.component" v-if="modalState" v-bind="modalState.props" v-model="isOpen" />
<component
:is="modalState.component"
v-if="modalState"
v-bind="modalState.props"
v-model="isOpen"
@after-leave="reset"
/>
</template>
<script lang="ts" setup>
@@ -8,5 +14,5 @@ import { useModal, modalInjectionKey } from '../../composables/useModal'
const modalState = inject(modalInjectionKey)
const { isOpen } = useModal()
const { isOpen, reset } = useModal()
</script>

View File

@@ -21,7 +21,7 @@
<div v-if="open" :class="[ui.overlay.base, ui.overlay.background]" />
</Transition>
<div v-if="open" ref="container" :class="[ui.container, ui.width]" :style="containerStyle">
<div v-if="open" ref="container" :class="[ui.container, ui.width]" :style="containerStyle" @mouseenter="onMouseEnter">
<Transition appear v-bind="ui.transition">
<div>
<div v-if="popper.arrow" data-popper-arrow :class="Object.values(ui.arrow)" />
@@ -154,8 +154,8 @@ export default defineComponent({
}
})
function onTouchStart () {
if (!popoverApi.value) {
function onTouchStart (event: TouchEvent) {
if (!event.cancelable || !popoverApi.value) {
return
}

View File

@@ -1,5 +1,5 @@
<template>
<TransitionRoot as="template" :appear="appear" :show="isOpen">
<TransitionRoot as="template" :appear="appear" :show="isOpen" @after-leave="onAfterLeave">
<HDialog :class="[ui.wrapper, { 'justify-end': side === 'right' }]" v-bind="attrs" @close="close">
<TransitionChild v-if="overlay" as="template" :appear="appear" v-bind="ui.overlay.transition">
<div :class="[ui.overlay.base, ui.overlay.background]" />
@@ -71,7 +71,7 @@ export default defineComponent({
default: () => ({})
}
},
emits: ['update:modelValue', 'close', 'close-prevented'],
emits: ['update:modelValue', 'close', 'close-prevented', 'after-leave'],
setup (props, { emit }) {
const { ui, attrs } = useUI('slideover', toRef(props, 'ui'), config, toRef(props, 'class'))
@@ -109,6 +109,10 @@ export default defineComponent({
emit('close')
}
const onAfterLeave = () => {
emit('after-leave')
}
provideUseId(() => useId())
return {
@@ -117,6 +121,7 @@ export default defineComponent({
attrs,
isOpen,
transitionClass,
onAfterLeave,
close
}
}

View File

@@ -4,6 +4,7 @@
v-if="slideoverState"
v-bind="slideoverState.props"
v-model="isOpen"
@after-leave="reset"
/>
</template>
@@ -13,5 +14,5 @@ import { useSlideover, slidOverInjectionKey } from '../../composables/useSlideov
const slideoverState = inject(slidOverInjectionKey)
const { isOpen } = useSlideover()
const { isOpen, reset } = useSlideover()
</script>

View File

@@ -8,19 +8,29 @@ export const modalInjectionKey: InjectionKey<ShallowRef<ModalState>> = Symbol('n
function _useModal () {
const modalState = inject(modalInjectionKey)
const isOpen = ref(false)
function open<T extends Component> (component: T, props?: Modal & ComponentProps<T>) {
if (!modalState) {
throw new Error('useModal() is called without provider')
}
modalState.value = {
component,
props: props ?? {}
}
isOpen.value = true
}
function close () {
async function close () {
if (!modalState) return
isOpen.value = false
}
function reset () {
modalState.value = {
component: 'div',
props: {}
@@ -31,6 +41,8 @@ function _useModal () {
* Allows updating the modal props
*/
function patch <T extends Component = {}> (props: Partial<Modal & ComponentProps<T>>) {
if (!modalState) return
modalState.value = {
...modalState.value,
props: {
@@ -41,11 +53,12 @@ function _useModal () {
}
return {
isOpen,
open,
close,
patch
reset,
patch,
isOpen
}
}
export const useModal = createSharedComposable(_useModal)
export const useModal = createSharedComposable(_useModal)

View File

@@ -1,55 +1,64 @@
import { ref, inject } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ComponentProps } from '../types/component'
import type { Slideover, SlideoverState } from '../types/slideover'
export const slidOverInjectionKey: InjectionKey<ShallowRef<SlideoverState>> =
Symbol('nuxt-ui.slideover')
export const slidOverInjectionKey: InjectionKey<ShallowRef<SlideoverState>> = Symbol('nuxt-ui.slideover')
function _useSlideover () {
const slideoverState = inject(slidOverInjectionKey)
const isOpen = ref(false)
const slideoverState = inject(slidOverInjectionKey)
function open<T extends Component> (component: T, props?: Slideover & ComponentProps<T>) {
if (!slideoverState) {
throw new Error('useSlideover() is called without provider')
}
const isOpen = ref(false)
slideoverState.value = {
component,
props: props ?? {}
}
isOpen.value = true
function open<T extends Component> (component: T, props?: Slideover & ComponentProps<T>) {
if (!slideoverState) {
throw new Error('useSlideover() is called without provider')
}
function close () {
if (!slideoverState) return
isOpen.value = false
slideoverState.value = {
component,
props: props ?? {}
}
/**
* Allows updating the slideover props
*/
function patch<T extends Component = {}> (props: Partial<Slideover & ComponentProps<T>>) {
if (!slideoverState) return
isOpen.value = true
}
slideoverState.value = {
...slideoverState.value,
props: {
...slideoverState.value.props,
...props
}
}
async function close () {
if (!slideoverState) return
isOpen.value = false
}
function reset () {
slideoverState.value = {
component: 'div',
props: {}
}
return {
open,
close,
patch,
isOpen
}
/**
* Allows updating the slideover props
*/
function patch<T extends Component = {}> (props: Partial<Slideover & ComponentProps<T>>) {
if (!slideoverState) return
slideoverState.value = {
...slideoverState.value,
props: {
...slideoverState.value.props,
...props
}
}
}
return {
open,
close,
reset,
patch,
isOpen
}
}
export const useSlideover = createSharedComposable(_useSlideover)

View File

@@ -9,7 +9,7 @@ export interface FormErrorWithId extends FormError {
id: string
}
export interface Form<T> {
export interface Form<T> extends HTMLFormElement {
validate(path?: string | string[], opts?: { silent?: true }): Promise<T | false>;
validate(path?: string | string[], opts?: { silent?: false }): Promise<T>;
clear(path?: string): void

View File

@@ -1,7 +1,7 @@
export default {
wrapper: {
base: 'flex items-center align-center text-center w-full',
horizontal: 'flex-row',
base: 'flex items-center align-center text-center',
horizontal: 'w-full flex-row',
vertical: 'flex-col'
},
container: {