mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-23 16:30:45 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24998e3ac5 | ||
|
|
bebf18a89a | ||
|
|
1b56b50d4d | ||
|
|
3337559b89 | ||
|
|
d33a23ebc0 | ||
|
|
28586c35a5 | ||
|
|
e521e1ac24 | ||
|
|
8ea3223071 | ||
|
|
4cbe983f61 | ||
|
|
e42969f003 | ||
|
|
c93e37a0eb | ||
|
|
9e20f96b65 | ||
|
|
9f6f132a76 | ||
|
|
5517cc2846 | ||
|
|
8c24b5dc97 | ||
|
|
ec8bd5cdc4 | ||
|
|
6fab68baa8 | ||
|
|
fc951e2980 | ||
|
|
08ff6e6c09 | ||
|
|
9dcdaf474e | ||
|
|
e9f0224b91 | ||
|
|
929192fd46 |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -2,6 +2,33 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.1.4](https://github.com/nuxtlabs/ui/compare/v0.1.3...v0.1.4) (2022-11-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **button:** support `RouteLocationRaw` type for `to` ([#112](https://github.com/nuxtlabs/ui/issues/112)) ([1b56b50](https://github.com/nuxtlabs/ui/commit/1b56b50d4d54a5cb9e5febacdf42867988ae6c5d))
|
||||||
|
|
||||||
|
### [0.1.3](https://github.com/nuxtlabs/ui/compare/v0.1.2...v0.1.3) (2022-11-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **docs:** component input string field ([e521e1a](https://github.com/nuxtlabs/ui/commit/e521e1ac2421dc331652f1ea4ac2b0b2959dc069))
|
||||||
|
* **types:** add missing field in command palette type ([#111](https://github.com/nuxtlabs/ui/issues/111)) ([28586c3](https://github.com/nuxtlabs/ui/commit/28586c35a558d9e925094f86e07acdb928d54ad7))
|
||||||
|
|
||||||
|
### [0.1.2](https://github.com/nuxtlabs/ui/compare/v0.1.1...v0.1.2) (2022-10-27)
|
||||||
|
|
||||||
|
### [0.1.1](https://github.com/nuxtlabs/ui/compare/v0.1.0...v0.1.1) (2022-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **CommandPalette:** lint ([6fab68b](https://github.com/nuxtlabs/ui/commit/6fab68baa836c97680446e8cfdee7c5a64008539))
|
||||||
|
* **Dropdown:** close on click item with `to` ([#103](https://github.com/nuxtlabs/ui/issues/103)) ([5517cc2](https://github.com/nuxtlabs/ui/commit/5517cc28467f957956a20126c1ce48e64677cb82))
|
||||||
|
* **Popover:** avoid crash on mount if ref not loaded ([#105](https://github.com/nuxtlabs/ui/issues/105)) ([e9f0224](https://github.com/nuxtlabs/ui/commit/e9f0224b919445260d3b19511420a3fd448e4ea7))
|
||||||
|
* **SelectCustom:** types and lint ([ec8bd5c](https://github.com/nuxtlabs/ui/commit/ec8bd5cdc49feb924dfdff352d9f3d788653c583))
|
||||||
|
|
||||||
## [0.1.0](https://github.com/nuxtlabs/ui/compare/v0.0.3...v0.1.0) (2022-10-25)
|
## [0.1.0](https://github.com/nuxtlabs/ui/compare/v0.0.3...v0.1.0) (2022-10-25)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<UButton variant="transparent" :icon="colorMode.value === 'dark' ? 'heroicons-outline:moon' : 'heroicons-outline:sun'" @click="toggleDark" />
|
<ColorScheme placeholder="" tag="span">
|
||||||
|
<UButton variant="transparent" :icon="colorMode.value === 'dark' ? 'heroicons-outline:moon' : 'heroicons-outline:sun'" @click="toggleDark" />
|
||||||
|
</ColorScheme>
|
||||||
<UButton to="https://github.com/nuxtlabs/ui" target="_blank" variant="transparent" icon="fa-brands:github" />
|
<UButton to="https://github.com/nuxtlabs/ui" target="_blank" variant="transparent" icon="fa-brands:github" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
|
|
||||||
<UContainer class="mt-16">
|
<UContainer class="mt-16">
|
||||||
<div class="lg:grid lg:grid-cols-10 lg:gap-10 lg:relative">
|
<div class="lg:grid lg:grid-cols-10 lg:gap-10 lg:relative">
|
||||||
<aside class="lg:flex lg:flex-col lg:relative pb-8 lg:pb-0 lg:sticky lg:top-0 px-4 sm:px-6 lg:px-0 lg:pt-16 lg:-mt-16 lg:self-start lg:col-span-2 lg:overflow-hidden lg:sticky lg:h-screen">
|
<aside class="lg:flex lg:flex-col pb-8 lg:pb-0 lg:sticky lg:top-0 px-4 sm:px-6 lg:px-0 lg:pt-16 lg:-mt-16 lg:self-start lg:col-span-2 lg:overflow-hidden lg:h-screen">
|
||||||
<nav class="overflow-y-auto h-auto pt-8 lg:py-12">
|
<nav class="overflow-y-auto h-auto pt-8 lg:py-12">
|
||||||
<ul class="space-y-6">
|
<ul class="space-y-6">
|
||||||
<li v-for="section of sections" :key="section">
|
<li v-for="section of sections" :key="section">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { defineNuxtConfig } from 'nuxt'
|
|
||||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||||
import nuxtUI from '../src/module'
|
import nuxtUI from '../src/module'
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- eslint-disable vue/no-template-shadow -->
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
|
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
|
||||||
<template>
|
<template>
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
<UInput
|
<UInput
|
||||||
v-else-if="prop.type === 'String' && typeof prop.value === 'string'"
|
v-else-if="prop.type === 'String'"
|
||||||
v-model="prop.value"
|
v-model="prop.value"
|
||||||
:name="prop.key"
|
:name="prop.key"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="pb-10 border-b u-border-gray-200 mb-10">
|
<div class="pb-10 border-b u-border-gray-200 mb-10">
|
||||||
@@ -153,8 +154,8 @@
|
|||||||
Tooltip:
|
Tooltip:
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UTooltip text="Hello tooltip!">
|
<UTooltip text="Hello tooltip!" :shortcuts="['⌘', 'G']">
|
||||||
<UIcon name="heroicons-outline:information-circle" class="w-6 h-6 text-black cursor-pointer" />
|
<UIcon name="heroicons-outline:information-circle" class="w-6 h-6 u-text-gray-900 cursor-pointer" />
|
||||||
</UTooltip>
|
</UTooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="pb-10 border-b u-border-gray-200 mb-10">
|
<div class="pb-10 border-b u-border-gray-200 mb-10">
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nuxthq/ui",
|
"name": "@nuxthq/ui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.4",
|
||||||
"repository": "https://github.com/nuxtlabs/ui",
|
"repository": "https://github.com/nuxtlabs/ui",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -24,28 +24,28 @@
|
|||||||
"release": "yarn lint && standard-version && git push --follow-tags"
|
"release": "yarn lint && standard-version && git push --follow-tags"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/vue": "^1.7.3",
|
"@headlessui/vue": "^1.7.4",
|
||||||
"@iconify/vue": "^4.0.0",
|
"@iconify/vue": "^4.0.0",
|
||||||
"@nuxt/kit": "^3.0.0-rc.12",
|
"@nuxt/kit": "^3.0.0-rc.13",
|
||||||
"@nuxtjs/color-mode": "^3.1.8",
|
"@nuxtjs/color-mode": "^3.1.8",
|
||||||
"@nuxtjs/tailwindcss": "^6.1.1",
|
"@nuxtjs/tailwindcss": "^6.1.3",
|
||||||
"@popperjs/core": "^2.11.6",
|
"@popperjs/core": "^2.11.6",
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
"@tailwindcss/line-clamp": "^0.4.2",
|
"@tailwindcss/line-clamp": "^0.4.2",
|
||||||
"@tailwindcss/typography": "^0.5.7",
|
"@tailwindcss/typography": "^0.5.8",
|
||||||
"@vueuse/core": "^9.3.1",
|
"@vueuse/core": "^9.4.0",
|
||||||
"@vueuse/integrations": "^9.3.1",
|
"@vueuse/integrations": "^9.4.0",
|
||||||
"defu": "^6.1.0",
|
"defu": "^6.1.0",
|
||||||
"fuse.js": "^6.6.2",
|
"fuse.js": "^6.6.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"tailwindcss": "^3.2.1"
|
"tailwindcss": "^3.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/module-builder": "^0.2.0",
|
"@nuxt/module-builder": "^0.2.0",
|
||||||
"@nuxtjs/eslint-config-typescript": "^11.0.0",
|
"@nuxtjs/eslint-config-typescript": "^11.0.0",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"eslint": "^8.26.0",
|
"eslint": "^8.27.0",
|
||||||
"nuxt": "^3.0.0-rc.9",
|
"nuxt": "^3.0.0-rc.9",
|
||||||
"standard-version": "^9.5.0",
|
"standard-version": "^9.5.0",
|
||||||
"vue-tsc": "^1.0.9"
|
"vue-tsc": "^1.0.9"
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ export default defineNuxtModule<ModuleOptions>({
|
|||||||
filename: 'ui.mjs',
|
filename: 'ui.mjs',
|
||||||
getContents: () => `export default ${JSON.stringify(ui)}`
|
getContents: () => `export default ${JSON.stringify(ui)}`
|
||||||
})
|
})
|
||||||
|
addTemplate({
|
||||||
|
filename: 'ui.d.ts',
|
||||||
|
write: true,
|
||||||
|
getContents: () => 'declare const d: any; export default d;'
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
await installModule('@nuxtjs/color-mode', { classSuffix: '' })
|
await installModule('@nuxtjs/color-mode', { classSuffix: '' })
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, useSlots } from 'vue'
|
import { ref, computed, useSlots } from 'vue'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { RouteLocationNormalized } from 'vue-router'
|
import type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
|
||||||
import NuxtLink from '#app/components/nuxt-link'
|
import NuxtLink from '#app/components/nuxt-link'
|
||||||
import Icon from '../elements/Icon.vue'
|
import Icon from '../elements/Icon.vue'
|
||||||
import { classNames } from '../../utils'
|
import { classNames } from '../../utils'
|
||||||
@@ -81,7 +81,7 @@ const props = defineProps({
|
|||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
type: [String, Object] as PropType<string | RouteLocationNormalized>,
|
type: [String, Object] as PropType<string | RouteLocationNormalized | RouteLocationRaw>,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
<transition appear v-bind="transitionClass">
|
<transition appear v-bind="transitionClass">
|
||||||
<MenuItems :class="baseClass" static>
|
<MenuItems :class="baseClass" static>
|
||||||
<div v-for="(subItems, index) of items" :key="index" :class="groupClass">
|
<div v-for="(subItems, index) of items" :key="index" :class="groupClass">
|
||||||
<MenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled }" :disabled="item.disabled" as="div">
|
<MenuItem v-for="(item, subIndex) of subItems" :key="subIndex" v-slot="{ active, disabled }" :disabled="item.disabled" @click="e => item.click?.(e)">
|
||||||
<Component v-bind="item" :is="(item.to && NuxtLink) || (item.click && 'button') || 'div'" :class="resolveItemClass({ active, disabled })" @click="e => onItemClick(e, item)">
|
<Component v-bind="item" :is="(item.to && NuxtLink) || (item.click && 'button') || 'div'" :class="resolveItemClass({ active, disabled })">
|
||||||
<slot :name="item.slot" :item="item">
|
<slot :name="item.slot" :item="item">
|
||||||
<Icon v-if="item.icon" :name="item.icon" :class="[itemIconClass, item.iconClass]" />
|
<Icon v-if="item.icon" :name="item.icon" :class="[itemIconClass, item.iconClass]" />
|
||||||
<Avatar v-if="item.avatar" v-bind="{ size: 'xxs', ...item.avatar }" :class="itemAvatarClass" />
|
<Avatar v-if="item.avatar" v-bind="{ size: 'xxs', ...item.avatar }" :class="itemAvatarClass" />
|
||||||
@@ -129,6 +129,14 @@ const props = defineProps({
|
|||||||
popperOptions: {
|
popperOptions: {
|
||||||
type: Object as PropType<PopperOptions>,
|
type: Object as PropType<PopperOptions>,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
},
|
||||||
|
openDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 50
|
||||||
|
},
|
||||||
|
closeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -144,17 +152,9 @@ function resolveItemClass ({ active, disabled }: { active: boolean, disabled: bo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onItemClick (e, item: any) {
|
// https://github.com/tailwindlabs/headlessui/blob/f66f4926c489fc15289d528294c23a3dc2aee7b1/packages/%40headlessui-vue/src/components/menu/menu.ts#L131
|
||||||
if (item.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.click) {
|
|
||||||
item.click(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const menuApi: Ref<any> = ref(null)
|
const menuApi: Ref<any> = ref(null)
|
||||||
|
|
||||||
let openTimeout: NodeJS.Timeout | null = null
|
let openTimeout: NodeJS.Timeout | null = null
|
||||||
let closeTimeout: NodeJS.Timeout | null = null
|
let closeTimeout: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ onMounted(() => {
|
|||||||
const menuProvidesSymbols = Object.getOwnPropertySymbols(menuProvides)
|
const menuProvidesSymbols = Object.getOwnPropertySymbols(menuProvides)
|
||||||
menuApi.value = menuProvidesSymbols.length && menuProvides[menuProvidesSymbols[0]]
|
menuApi.value = menuProvidesSymbols.length && menuProvides[menuProvidesSymbols[0]]
|
||||||
// stop trigger click propagation on hover
|
// stop trigger click propagation on hover
|
||||||
menuApi.value?.buttonRef.addEventListener('click', (e: Event) => {
|
menuApi.value?.buttonRef?.addEventListener('click', (e: Event) => {
|
||||||
if (props.mode === 'hover') {
|
if (props.mode === 'hover') {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ function onMouseOver () {
|
|||||||
openTimeout = openTimeout || setTimeout(() => {
|
openTimeout = openTimeout || setTimeout(() => {
|
||||||
menuApi.value.openMenu && menuApi.value.openMenu()
|
menuApi.value.openMenu && menuApi.value.openMenu()
|
||||||
openTimeout = null
|
openTimeout = null
|
||||||
}, 50)
|
}, props.openDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseLeave () {
|
function onMouseLeave () {
|
||||||
@@ -212,7 +212,7 @@ function onMouseLeave () {
|
|||||||
closeTimeout = closeTimeout || setTimeout(() => {
|
closeTimeout = closeTimeout || setTimeout(() => {
|
||||||
menuApi.value.closeMenu && menuApi.value.closeMenu()
|
menuApi.value.closeMenu && menuApi.value.closeMenu()
|
||||||
closeTimeout = null
|
closeTimeout = null
|
||||||
}, 0)
|
}, props.closeDelay)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
>
|
>
|
||||||
<input :value="modelValue" :required="required" class="absolute inset-0 w-px opacity-0 cursor-default" tabindex="-1">
|
<input :value="modelValue" :required="required" class="absolute inset-0 w-px opacity-0 cursor-default" tabindex="-1">
|
||||||
|
|
||||||
<ComboboxButton ref="trigger" v-slot="{ disabled }" as="div">
|
<ComboboxButton ref="trigger" v-slot="{ disabled: buttonDisabled }" as="div">
|
||||||
<slot :open="open" :disabled="disabled">
|
<slot :open="open" :disabled="buttonDisabled">
|
||||||
<button :class="selectCustomClass" :disabled="disabled" type="button">
|
<button :class="selectCustomClass" :disabled="disabled" type="button">
|
||||||
<slot name="label">
|
<slot name="label">
|
||||||
<span v-if="modelValue" class="block truncate">{{ modelValue[textAttribute] }}</span>
|
<span v-if="modelValue" class="block truncate">{{ modelValue[textAttribute] }}</span>
|
||||||
@@ -44,13 +44,13 @@
|
|||||||
/>
|
/>
|
||||||
<ComboboxOption
|
<ComboboxOption
|
||||||
v-for="(option, index) in filteredOptions"
|
v-for="(option, index) in filteredOptions"
|
||||||
v-slot="{ active, selected, disabled }"
|
v-slot="{ active, selected, disabled: optionDisabled }"
|
||||||
:key="index"
|
:key="index"
|
||||||
as="template"
|
as="template"
|
||||||
:value="option"
|
:value="option"
|
||||||
:disabled="option.disabled"
|
:disabled="option.disabled"
|
||||||
>
|
>
|
||||||
<li :class="resolveOptionClass({ active, selected, disabled })">
|
<li :class="resolveOptionClass({ active, selected, disabled: optionDisabled })">
|
||||||
<div :class="listOptionContainerClass">
|
<div :class="listOptionContainerClass">
|
||||||
<slot name="option" :option="option" :active="active" :selected="selected">
|
<slot name="option" :option="option" :active="active" :selected="selected">
|
||||||
<span class="block truncate">{{ option[textAttribute] }}</span>
|
<span class="block truncate">{{ option[textAttribute] }}</span>
|
||||||
@@ -110,7 +110,7 @@ const props = defineProps({
|
|||||||
default: undefined
|
default: undefined
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<{ disabled?: boolean }[]>,
|
type: Array as PropType<{ [key: string]: any, disabled?: boolean }[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
required: {
|
required: {
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ const groups = computed(() => map(groupBy(results.value, command => command.item
|
|||||||
return {
|
return {
|
||||||
...props.groups.find(group => group.key === key),
|
...props.groups.find(group => group.key === key),
|
||||||
commands: commands.slice(0, options.value.resultLimit)
|
commands: commands.slice(0, options.value.resultLimit)
|
||||||
}
|
} as Group
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
<div class="flex items-center gap-1.5 min-w-0" :class="{ 'opacity-50': command.disabled }">
|
<div class="flex items-center gap-1.5 min-w-0" :class="{ 'opacity-50': command.disabled }">
|
||||||
<slot :name="`${group.key}-command`" :group="group" :command="command">
|
<slot :name="`${group.key}-command`" :group="group" :command="command">
|
||||||
<span v-if="command.prefix" class="u-text-gray-400">{{ command.prefix }}</span>
|
<span v-if="command.prefix" class="u-text-gray-400">{{ command.prefix }}</span>
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<span v-if="command.matches?.length" class="truncate" :class="{ 'flex-none': command.suffix }" v-html="highlight(command.matches[0])" />
|
<span v-if="command.matches?.length" class="truncate" :class="{ 'flex-none': command.suffix }" v-html="highlight(command.matches[0])" />
|
||||||
<span v-else class="truncate" :class="{ 'flex-none': command.suffix }">{{ command[commandAttribute] }}</span>
|
<span v-else class="truncate" :class="{ 'flex-none': command.suffix }">{{ command[commandAttribute] }}</span>
|
||||||
<span v-if="command.suffix" class="u-text-gray-400 truncate">{{ command.suffix }}</span>
|
<span v-if="command.suffix" class="u-text-gray-400 truncate">{{ command.suffix }}</span>
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType, computed, toRef } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
|
import { computed, toRef } from 'vue'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import { usePopper } from '../../composables/usePopper'
|
import { usePopper } from '../../composables/usePopper'
|
||||||
import type { PopperOptions } from '../../types'
|
import type { PopperOptions } from '../../types'
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ const props = defineProps({
|
|||||||
popperOptions: {
|
popperOptions: {
|
||||||
type: Object as PropType<PopperOptions>,
|
type: Object as PropType<PopperOptions>,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
},
|
||||||
|
openDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 50
|
||||||
|
},
|
||||||
|
closeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -63,6 +71,7 @@ const popperOptions = computed<PopperOptions>(() => defu({}, props.popperOptions
|
|||||||
|
|
||||||
const [trigger, container] = usePopper(popperOptions.value)
|
const [trigger, container] = usePopper(popperOptions.value)
|
||||||
|
|
||||||
|
// https://github.com/tailwindlabs/headlessui/blob/f66f4926c489fc15289d528294c23a3dc2aee7b1/packages/%40headlessui-vue/src/components/popover/popover.ts#L151
|
||||||
const popoverApi: Ref<any> = ref(null)
|
const popoverApi: Ref<any> = ref(null)
|
||||||
|
|
||||||
let openTimeout: NodeJS.Timeout | null = null
|
let openTimeout: NodeJS.Timeout | null = null
|
||||||
@@ -77,7 +86,7 @@ onMounted(() => {
|
|||||||
const popoverProvidesSymbols = Object.getOwnPropertySymbols(popoverProvides)
|
const popoverProvidesSymbols = Object.getOwnPropertySymbols(popoverProvides)
|
||||||
popoverApi.value = popoverProvidesSymbols.length && popoverProvides[popoverProvidesSymbols[0]]
|
popoverApi.value = popoverProvidesSymbols.length && popoverProvides[popoverProvidesSymbols[0]]
|
||||||
// stop trigger click propagation on hover
|
// stop trigger click propagation on hover
|
||||||
popoverApi.value.button.addEventListener('click', (e: Event) => {
|
popoverApi.value?.button?.addEventListener('click', (e: Event) => {
|
||||||
if (props.mode === 'hover') {
|
if (props.mode === 'hover') {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
@@ -89,6 +98,7 @@ function onMouseOver () {
|
|||||||
if (props.mode !== 'hover' || !popoverApi.value) {
|
if (props.mode !== 'hover' || !popoverApi.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel programmed closing
|
// cancel programmed closing
|
||||||
if (closeTimeout) {
|
if (closeTimeout) {
|
||||||
clearTimeout(closeTimeout)
|
clearTimeout(closeTimeout)
|
||||||
@@ -101,13 +111,14 @@ function onMouseOver () {
|
|||||||
openTimeout = openTimeout || setTimeout(() => {
|
openTimeout = openTimeout || setTimeout(() => {
|
||||||
popoverApi.value.togglePopover && popoverApi.value.togglePopover()
|
popoverApi.value.togglePopover && popoverApi.value.togglePopover()
|
||||||
openTimeout = null
|
openTimeout = null
|
||||||
}, 50)
|
}, props.openDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseLeave () {
|
function onMouseLeave () {
|
||||||
if (props.mode !== 'hover' || !popoverApi.value) {
|
if (props.mode !== 'hover' || !popoverApi.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel programmed opening
|
// cancel programmed opening
|
||||||
if (openTimeout) {
|
if (openTimeout) {
|
||||||
clearTimeout(openTimeout)
|
clearTimeout(openTimeout)
|
||||||
@@ -120,7 +131,7 @@ function onMouseLeave () {
|
|||||||
closeTimeout = closeTimeout || setTimeout(() => {
|
closeTimeout = closeTimeout || setTimeout(() => {
|
||||||
popoverApi.value.closePopover && popoverApi.value.closePopover()
|
popoverApi.value.closePopover && popoverApi.value.closePopover()
|
||||||
closeTimeout = null
|
closeTimeout = null
|
||||||
}, 0)
|
}, props.closeDelay)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="trigger" :class="wrapperClass" @mouseover="open = true" @mouseleave="open = false">
|
<div ref="trigger" :class="wrapperClass" @mouseover="onMouseOver" @mouseleave="onMouseLeave">
|
||||||
<slot :open="open">
|
<slot :open="open">
|
||||||
Hover me
|
Hover me
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<div v-if="open" ref="container" :class="[containerClass, widthClass]">
|
<div v-if="open" ref="container" :class="[containerClass, widthClass]">
|
||||||
<transition appear v-bind="transitionClass">
|
<transition appear v-bind="transitionClass">
|
||||||
<div :class="baseClass">
|
<div :class="[baseClass, backgroundClass, roundedClass, shadowClass, ringClass]">
|
||||||
<slot name="text">
|
<slot name="text">
|
||||||
{{ text }}
|
<span class="truncate">{{ text }}</span>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
|
<span v-if="shortcuts?.length" class="inline-flex items-center justify-end flex-shrink-0 gap-0.5 ml-1">
|
||||||
|
<span class="mr-1 u-text-gray-700">·</span>
|
||||||
|
<kbd v-for="shortcut of shortcuts" :key="shortcut" class="flex items-center justify-center font-sans px-1 h-4 min-w-[16px] text-[10px] u-bg-gray-100 rounded u-text-gray-900">
|
||||||
|
{{ shortcut }}
|
||||||
|
</kbd>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,6 +36,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
shortcuts: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
wrapperClass: {
|
wrapperClass: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => $ui.tooltip.wrapper
|
default: () => $ui.tooltip.wrapper
|
||||||
@@ -41,6 +52,22 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: () => $ui.tooltip.width
|
default: () => $ui.tooltip.width
|
||||||
},
|
},
|
||||||
|
backgroundClass: {
|
||||||
|
type: String,
|
||||||
|
default: () => $ui.tooltip.background
|
||||||
|
},
|
||||||
|
shadowClass: {
|
||||||
|
type: String,
|
||||||
|
default: () => $ui.tooltip.shadow
|
||||||
|
},
|
||||||
|
ringClass: {
|
||||||
|
type: String,
|
||||||
|
default: () => $ui.tooltip.ring
|
||||||
|
},
|
||||||
|
roundedClass: {
|
||||||
|
type: String,
|
||||||
|
default: () => $ui.tooltip.rounded
|
||||||
|
},
|
||||||
baseClass: {
|
baseClass: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => $ui.tooltip.base
|
default: () => $ui.tooltip.base
|
||||||
@@ -52,6 +79,14 @@ const props = defineProps({
|
|||||||
popperOptions: {
|
popperOptions: {
|
||||||
type: Object as PropType<PopperOptions>,
|
type: Object as PropType<PopperOptions>,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
},
|
||||||
|
openDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
closeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -60,6 +95,43 @@ const popperOptions = computed<PopperOptions>(() => defu({}, props.popperOptions
|
|||||||
const [trigger, container] = usePopper(popperOptions.value)
|
const [trigger, container] = usePopper(popperOptions.value)
|
||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false)
|
||||||
|
|
||||||
|
let openTimeout: NodeJS.Timeout | null = null
|
||||||
|
let closeTimeout: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
|
||||||
|
function onMouseOver () {
|
||||||
|
// cancel programmed closing
|
||||||
|
if (closeTimeout) {
|
||||||
|
clearTimeout(closeTimeout)
|
||||||
|
closeTimeout = null
|
||||||
|
}
|
||||||
|
// dropdown already open
|
||||||
|
if (open.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
openTimeout = openTimeout || setTimeout(() => {
|
||||||
|
open.value = true
|
||||||
|
openTimeout = null
|
||||||
|
}, props.openDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseLeave () {
|
||||||
|
// cancel programmed opening
|
||||||
|
if (openTimeout) {
|
||||||
|
clearTimeout(openTimeout)
|
||||||
|
openTimeout = null
|
||||||
|
}
|
||||||
|
// dropdown already closed
|
||||||
|
if (!open.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
closeTimeout = closeTimeout || setTimeout(() => {
|
||||||
|
open.value = false
|
||||||
|
closeTimeout = null
|
||||||
|
}, props.closeDelay)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ export default (variantColors: string[]) => {
|
|||||||
wrapper: 'relative inline-flex text-left',
|
wrapper: 'relative inline-flex text-left',
|
||||||
container: 'z-20',
|
container: 'z-20',
|
||||||
width: 'w-48',
|
width: 'w-48',
|
||||||
base: 'u-bg-white divide-y u-divide-gray-100 rounded-md ring-1 u-ring-gray-200 shadow-lg',
|
base: 'u-bg-white divide-y u-divide-gray-100 rounded-md ring-1 u-ring-gray-200 shadow-lg focus:outline-none',
|
||||||
group: 'py-1',
|
group: 'py-1',
|
||||||
item: {
|
item: {
|
||||||
base: 'group flex items-center gap-3 px-4 py-2 text-sm w-full',
|
base: 'group flex items-center gap-3 px-4 py-2 text-sm w-full',
|
||||||
@@ -487,7 +487,11 @@ export default (variantColors: string[]) => {
|
|||||||
wrapper: 'relative inline-flex',
|
wrapper: 'relative inline-flex',
|
||||||
container: 'z-20',
|
container: 'z-20',
|
||||||
width: 'max-w-xs',
|
width: 'max-w-xs',
|
||||||
base: 'invisible w-auto h-6 px-2 py-1 space-x-1 truncate rounded shadow lg:visible u-bg-gray-800 truncate u-text-gray-50 text-xs',
|
background: 'u-bg-white',
|
||||||
|
shadow: 'shadow',
|
||||||
|
rounded: 'rounded',
|
||||||
|
ring: 'ring-1 u-ring-gray-200',
|
||||||
|
base: 'invisible lg:visible h-6 px-2 py-1 text-xs font-normal',
|
||||||
transition: {
|
transition: {
|
||||||
enterActiveClass: 'transition ease-out duration-200',
|
enterActiveClass: 'transition ease-out duration-200',
|
||||||
enterFromClass: 'opacity-0 translate-y-1',
|
enterFromClass: 'opacity-0 translate-y-1',
|
||||||
|
|||||||
7
src/runtime/types/command-palette.d.ts
vendored
7
src/runtime/types/command-palette.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
import type { UseFuseOptions } from '@vueuse/integrations/useFuse'
|
import type { UseFuseOptions } from '@vueuse/integrations/useFuse'
|
||||||
|
import type { FuseSortFunctionMatch, FuseSortFunctionMatchList } from 'fuse.js'
|
||||||
import type { Avatar } from './avatar'
|
import type { Avatar } from './avatar'
|
||||||
|
|
||||||
export interface Command {
|
export interface Command {
|
||||||
id: string | number
|
id: string | number
|
||||||
prefix?: string
|
prefix?: string
|
||||||
@@ -11,6 +11,10 @@ export interface Command {
|
|||||||
chip?: string
|
chip?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
shortcuts?: string[]
|
shortcuts?: string[]
|
||||||
|
group?: string
|
||||||
|
score?: number
|
||||||
|
matches?: (FuseSortFunctionMatch | FuseSortFunctionMatchList)[]
|
||||||
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Group {
|
export interface Group {
|
||||||
@@ -19,4 +23,5 @@ export interface Group {
|
|||||||
inactive?: string
|
inactive?: string
|
||||||
commands: Command[]
|
commands: Command[]
|
||||||
options?: Partial<UseFuseOptions<Command>>
|
options?: Partial<UseFuseOptions<Command>>
|
||||||
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user