Skip to content

Commit 7bd7a1e

Browse files
committed
chore: wip
1 parent ab29828 commit 7bd7a1e

File tree

10 files changed

+651
-139
lines changed

10 files changed

+651
-139
lines changed

docs/components/combobox.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
<ComboboxDemo />
44

5-
For more detailed documentation and examples, please visit our documentation site.
5+
Still have questions relating this component's usage? Contact us and we will help you out. In the meantime, if you are curious about the `Combobox Component` read more on the next page.

docs/components/dialog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
<DialogDemo />
44

5-
For more detailed documentation and examples, please visit our documentation site.
5+
Still have questions relating this component's usage? Contact us and we will help you out. In the meantime, if you are curious about the `Dialog Component` read more on the next page.

resources/components/Docs/ComboboxDemo.vue

Lines changed: 0 additions & 132 deletions
This file was deleted.

storage/framework/core/components/combobox/components.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
// @ts-nocheck
33
// Generated by unplugin-vue-components
44
// Read more: https://github.com/vuejs/core/pull/3399
5+
// biome-ignore lint: disable
56
export {}
67

78
/* prettier-ignore */
89
declare module 'vue' {
910
export interface GlobalComponents {
11+
'Carbon:cafe': typeof import('~icons/carbon/cafe')['default']
12+
'Carbon:logoTwitter': typeof import('~icons/carbon/logo-twitter')['default']
13+
'Mdi:heart': typeof import('~icons/mdi/heart')['default']
1014
RouterLink: typeof import('vue-router')['RouterLink']
1115
RouterView: typeof import('vue-router')['RouterView']
1216
Starport: typeof import('vue-starport')['Starport']
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<script lang="ts" setup>
2+
import {
3+
Combobox,
4+
ComboboxButton,
5+
ComboboxInput,
6+
ComboboxOption,
7+
ComboboxOptions,
8+
} from '@stacksjs/combobox'
9+
10+
import { TransitionRoot } from '@stacksjs/transition'
11+
import { computed, ref } from 'vue'
12+
13+
interface Person {
14+
id: number
15+
name: string
16+
}
17+
18+
const defaultItems = [
19+
{ id: 1, name: 'Chris Breuer' },
20+
{ id: 2, name: 'Avery Hill' },
21+
{ id: 3, name: 'Glenn Michael' },
22+
{ id: 4, name: 'Michael Vincent' },
23+
{ id: 5, name: 'Blake Ayer' },
24+
]
25+
26+
const listItems = ref<Person[]>(defaultItems)
27+
const selected = ref<Person | null>(null)
28+
const query = ref('')
29+
const isOpen = ref(false)
30+
31+
const items = computed(() => {
32+
return query.value === ''
33+
? listItems.value
34+
: listItems.value.filter((item) =>
35+
item.name.toLowerCase().includes(query.value.toLowerCase())
36+
)
37+
})
38+
39+
const handleInput = (event: Event) => {
40+
const target = event.target as HTMLInputElement
41+
query.value = target.value
42+
isOpen.value = true
43+
}
44+
45+
const handleSelect = (person: Person) => {
46+
selected.value = person
47+
isOpen.value = false
48+
}
49+
50+
const formatInput = (text: string) => {
51+
return text.trim()
52+
.split('\n')
53+
.filter(line => line.length > 0)
54+
.map((name, index) => ({
55+
id: listItems.value.length + index + 1,
56+
name,
57+
}))
58+
}
59+
60+
const updateItems = (event: Event) => {
61+
const target = event.target as HTMLTextAreaElement
62+
const newItems = formatInput(target.value)
63+
listItems.value = newItems
64+
}
65+
</script>
66+
67+
<template>
68+
<div class="flex flex-col gap-6 my-10 max-w-md ">
69+
<div class="flex flex-col gap-2">
70+
<h2 class="text-2xl font-bold text-gray-900">Combobox Demo</h2>
71+
<p class="text-gray-600">Search and select a person from the list</p>
72+
</div>
73+
74+
<div class="relative">
75+
<Combobox v-model="selected" as="div" class="relative">
76+
<div class="relative">
77+
<ComboboxInput
78+
class="w-full py-2.5 pl-3 pr-10 text-base text-gray-900 placeholder-gray-400 bg-white border border-gray-300 rounded-lg shadow-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-200"
79+
:display-value="(person: Person) => person?.name"
80+
placeholder="Search people..."
81+
@change="handleInput"
82+
@focus="isOpen = true"
83+
/>
84+
<ComboboxButton
85+
class="absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400 hover:text-gray-500"
86+
>
87+
<div class="i-heroicons-chevron-up-down-20-solid w-5 h-5" />
88+
</ComboboxButton>
89+
</div>
90+
91+
<TransitionRoot
92+
:show="isOpen"
93+
leave="transition ease-in duration-100"
94+
leave-from="opacity-100"
95+
leave-to="opacity-0"
96+
@after-leave="query = ''"
97+
>
98+
<ComboboxOptions
99+
class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none"
100+
>
101+
<div
102+
v-if="items.length === 0"
103+
class="relative cursor-default select-none px-4 py-2 text-gray-700"
104+
>
105+
No results found.
106+
</div>
107+
108+
<ComboboxOption
109+
v-for="item in items"
110+
:key="item.id"
111+
:value="item"
112+
v-slot="{ selected: isSelected, active }"
113+
as="template"
114+
@click="handleSelect(item)"
115+
>
116+
<li
117+
class="relative cursor-default select-none py-2 pl-10 pr-4"
118+
:class="{
119+
'bg-indigo-600 text-white': active,
120+
'text-gray-900': !active,
121+
}"
122+
>
123+
<span
124+
class="block truncate"
125+
:class="{ 'font-medium': isSelected, 'font-normal': !isSelected }"
126+
>
127+
{{ item.name }}
128+
</span>
129+
<span
130+
v-if="isSelected"
131+
class="absolute inset-y-0 left-0 flex items-center pl-3"
132+
:class="{ 'text-white': active, 'text-indigo-600': !active }"
133+
>
134+
<div class="i-heroicons-check-20-solid w-5 h-5" />
135+
</span>
136+
</li>
137+
</ComboboxOption>
138+
</ComboboxOptions>
139+
</TransitionRoot>
140+
</Combobox>
141+
</div>
142+
143+
<div v-if="selected" class="mt-4 p-4 bg-gray-50 rounded-lg border border-gray-200">
144+
<h3 class="text-sm font-medium text-gray-500">Selected Person</h3>
145+
<div class="mt-1 flex items-center gap-2">
146+
<span class="text-lg font-semibold text-gray-900">{{ selected.name }}</span>
147+
<span class="text-sm text-gray-500">(ID: {{ selected.id }})</span>
148+
</div>
149+
</div>
150+
151+
<div class="mt-8">
152+
<div class="flex flex-col gap-2">
153+
<label for="items-input" class="block text-lg font-medium text-gray-900">
154+
Edit List Items
155+
</label>
156+
<p class="text-sm text-gray-500">Enter each name on a new line</p>
157+
</div>
158+
<textarea
159+
id="items-input"
160+
rows="4"
161+
:value="listItems.map(item => item.name).join('\n')"
162+
@input="updateItems"
163+
class="mt-2 w-full rounded-lg border border-gray-300 bg-white px-4 py-2 text-gray-900 shadow-sm placeholder-gray-400 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-200"
164+
placeholder="Type your list here..."
165+
/>
166+
</div>
167+
</div>
168+
</template>

0 commit comments

Comments
 (0)