Skip to content
Open
14 changes: 12 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solid-ui",
"version": "3.1.3-9",
"version": "3.1.3-10",
"description": "UI library for Solid applications",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -93,6 +93,7 @@
"dependencies": {
"@awesome.me/webawesome": "^3.9.0",
"@lit/context": "^1.1.6",
"@lit/task": "^1.0.3",
"@noble/curves": "^2.2.0",
"@noble/hashes": "^2.2.0",
"escape-html": "^1.0.3",
Expand Down
80 changes: 72 additions & 8 deletions src/components/combobox/Combobox.stories.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { html } from 'lit'
import { defineStoryRender } from '@/storybook'
import { defineAsyncComboboxOptionsProvider } from './Combobox'

import '@/components/combobox-option'

Expand All @@ -9,24 +10,87 @@ const meta = {
title: 'Combobox',
args: {
label: 'What is the best food?',
options: 'Pizza, Ramen, Tacos'
options: 'Pizza, Ramen, Tacos',
asyncJSOptions: false,
asyncHtmlOptions: false,
},
argTypes: {
label: { control: 'text' },
options: { control: 'text' },
asyncJSOptions: { control: 'boolean' },
asyncHtmlOptions: { control: 'boolean' },
},
} as const

const render = defineStoryRender<typeof meta.argTypes>(({ label, options }) => {
const parsedOptions = options.split(',').map(option => option.trim())
const pokemonProvider = defineAsyncComboboxOptionsProvider(async (query) => {
const response = await fetch('https://beta.pokeapi.co/graphql/v1beta', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `
query searchPokemon($search: String!) {
pokemon_v2_pokemon(where: {name: {_ilike: $search}}, limit: 20) {
id
name
}
}
`,
variables: { search: `%${query}%` },
}),
})

return html`
<solid-ui-combobox label="${label}">
${parsedOptions.map(option => html`<solid-ui-combobox-option value="${option}">${option}</solid-ui-combobox-option>`)}
</solid-ui-combobox>
`
const { data } = await response.json()

return data.pokemon_v2_pokemon.map(pokemon => ({
value: pokemon.id.toString(),
label: pokemon.name.charAt(0).toUpperCase() + pokemon.name.slice(1),
}))
})

const render = defineStoryRender<typeof meta.argTypes>(
({ label, options, asyncJSOptions, asyncHtmlOptions }) => {
if (asyncJSOptions) {
return html`<solid-ui-combobox label="${label}" .asyncOptionsProvider=${pokemonProvider}></solid-ui-combobox>`
}

if (asyncHtmlOptions) {
return html`
<solid-ui-combobox
label="${label}"
async-options-url="https://api.disneyapi.dev/character?name=%search%"
async-options-results-field="data"
async-options-label-field="name"
async-options-value-field="_id"
></solid-ui-combobox>
`
}

const parsedOptions = options.split(',').map((option) => option.trim())

return html`
<solid-ui-combobox label="${label}">
${parsedOptions.map((option) => html`<solid-ui-combobox-option value="${option}">${option}</solid-ui-combobox-option>`)}
</solid-ui-combobox>
`
}
)

export default meta

export const Primary = { render }

export const AsyncWithJS = {
args: {
label: 'Who is the best Pokemon?',
asyncJSOptions: true,
},
render,
}

export const AsyncWithHtml = {
args: {
label: 'Who is the best Disney character?',
asyncHtmlOptions: true,
},
render,
}
21 changes: 19 additions & 2 deletions src/components/combobox/Combobox.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@
max-height: inherit;
overflow: auto;

[role="option"] {
padding: 12px 8px;
[role="option"], .non-selectable-option {
color: var(--solid-ui-color-gray-700);
padding: 12px 8px;
}

[role="option"] {
border-bottom: 1px solid var(--solid-ui-color-gray-100);
cursor: pointer;

Expand All @@ -64,5 +67,19 @@
background: rgba(0, 0, 0, 0.05);
}
}

.non-selectable-option {
display: flex;
justify-content: center;
align-items: center;

icon-svg-spinners-3-dots-fade {
width: 2rem;
}

.message--error {
color: var(--solid-ui-color-error);
}
}
}
}
Loading
Loading