366 lines
11 KiB
Markdown
366 lines
11 KiB
Markdown
# Select
|
|
|
|
Dropdown select component with full DaisyUI styling, reactive items, and form integration.
|
|
|
|
## Tag
|
|
|
|
`Select`
|
|
|
|
## Props
|
|
|
|
| Prop | Type | Default | Description |
|
|
| :----------- | :-------------------------------------- | :------------------ | :----------------------------------------------- |
|
|
| `label` | `string` | `-` | Label text above select |
|
|
| `items` | `Array<{value: string, label: string}>` | `[]` | Array of items with value and label |
|
|
| `value` | `string \| Signal<string>` | `''` | Selected value |
|
|
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
|
|
| `disabled` | `boolean \| Signal<boolean>` | `false` | Disabled state |
|
|
| `onchange` | `function` | `-` | Change event handler |
|
|
|
|
## Live Examples
|
|
|
|
### Basic Select
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const BasicDemo = () => {
|
|
const selected = $('apple');
|
|
|
|
return Select({
|
|
label: 'Choose a fruit',
|
|
items: [
|
|
{ value: 'apple', label: '🍎 Apple' },
|
|
{ value: 'banana', label: '🍌 Banana' },
|
|
{ value: 'orange', label: '🍊 Orange' },
|
|
{ value: 'grape', label: '🍇 Grape' }
|
|
],
|
|
value: selected,
|
|
onchange: (e) => selected(e.target.value)
|
|
});
|
|
};
|
|
$mount(BasicDemo, '#demo-basic');
|
|
```
|
|
|
|
### With Reactive Display
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-reactive" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-4"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const ReactiveDemo = () => {
|
|
const selected = $('small');
|
|
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
|
Select({
|
|
label: 'Select size',
|
|
items: [
|
|
{ value: 'small', label: 'Small' },
|
|
{ value: 'medium', label: 'Medium' },
|
|
{ value: 'large', label: 'Large' }
|
|
],
|
|
value: selected,
|
|
onchange: (e) => selected(e.target.value)
|
|
}),
|
|
Div({ class: 'alert alert-info' }, [
|
|
() => `You selected: ${selected()}`
|
|
])
|
|
]);
|
|
};
|
|
$mount(ReactiveDemo, '#demo-reactive');
|
|
```
|
|
|
|
### Disabled State
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-disabled" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const DisabledDemo = () => {
|
|
return Select({
|
|
label: 'Country (disabled)',
|
|
items: [
|
|
{ value: 'mx', label: 'Mexico' },
|
|
{ value: 'us', label: 'United States' },
|
|
{ value: 'ca', label: 'Canada' }
|
|
],
|
|
value: 'mx',
|
|
disabled: true
|
|
});
|
|
};
|
|
$mount(DisabledDemo, '#demo-disabled');
|
|
```
|
|
|
|
### Dynamic items
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-dynamic" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const DynamicDemo = () => {
|
|
const category = $('fruits');
|
|
|
|
const items = {
|
|
fruits: [
|
|
{ value: 'apple', label: '🍎 Apple' },
|
|
{ value: 'banana', label: '🍌 Banana' }
|
|
],
|
|
vegetables: [
|
|
{ value: 'carrot', label: '🥕 Carrot' },
|
|
{ value: 'broccoli', label: '🥦 Broccoli' }
|
|
]
|
|
};
|
|
|
|
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
|
Select({
|
|
label: 'Category',
|
|
items: [
|
|
{ value: 'fruits', label: 'Fruits' },
|
|
{ value: 'vegetables', label: 'Vegetables' }
|
|
],
|
|
value: category,
|
|
onchange: (e) => category(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Item',
|
|
items: () => items[category()] || [],
|
|
value: $(''),
|
|
onchange: (e) => console.log('Selected:', e.target.value)
|
|
})
|
|
]);
|
|
};
|
|
$mount(DynamicDemo, '#demo-dynamic');
|
|
```
|
|
|
|
### All Variants
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-4"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const VariantsDemo = () => {
|
|
const primary = $('option1');
|
|
const secondary = $('option2');
|
|
const accent = $('');
|
|
|
|
return Div({ class: 'flex flex-col gap-4' }, [
|
|
Select({
|
|
label: 'Primary Select',
|
|
class: 'select-primary',
|
|
items: [
|
|
{ value: 'option1', label: 'Option 1' },
|
|
{ value: 'option2', label: 'Option 2' },
|
|
{ value: 'option3', label: 'Option 3' }
|
|
],
|
|
value: primary,
|
|
onchange: (e) => primary(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Secondary Select',
|
|
class: 'select-secondary',
|
|
items: [
|
|
{ value: 'option1', label: 'Option 1' },
|
|
{ value: 'option2', label: 'Option 2' }
|
|
],
|
|
value: secondary,
|
|
onchange: (e) => secondary(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Ghost Select',
|
|
class: 'select-ghost',
|
|
items: [
|
|
{ value: '', label: 'Select an option' },
|
|
{ value: 'opt1', label: 'Option 1' },
|
|
{ value: 'opt2', label: 'Option 2' }
|
|
],
|
|
value: accent,
|
|
onchange: (e) => accent(e.target.value)
|
|
})
|
|
]);
|
|
};
|
|
$mount(VariantsDemo, '#demo-variants');
|
|
```
|
|
|
|
<script>
|
|
(function() {
|
|
const initSelectExamples = () => {
|
|
|
|
// 1. Basic Select
|
|
const basicTarget = document.querySelector('#demo-basic');
|
|
if (basicTarget && !basicTarget.hasChildNodes()) {
|
|
const BasicDemo = () => {
|
|
const selected = $('apple');
|
|
|
|
return Select({
|
|
label: 'Choose a fruit',
|
|
items: [
|
|
{ value: 'apple', label: '🍎 Apple' },
|
|
{ value: 'banana', label: '🍌 Banana' },
|
|
{ value: 'orange', label: '🍊 Orange' },
|
|
{ value: 'grape', label: '🍇 Grape' }
|
|
],
|
|
value: selected,
|
|
onchange: (e) => selected(e.target.value)
|
|
});
|
|
};
|
|
$mount(BasicDemo, basicTarget);
|
|
}
|
|
|
|
// 2. Reactive Display
|
|
const reactiveTarget = document.querySelector('#demo-reactive');
|
|
if (reactiveTarget && !reactiveTarget.hasChildNodes()) {
|
|
const ReactiveDemo = () => {
|
|
const selected = $('small');
|
|
|
|
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
|
Select({
|
|
label: 'Select size',
|
|
items: [
|
|
{ value: 'small', label: 'Small' },
|
|
{ value: 'medium', label: 'Medium' },
|
|
{ value: 'large', label: 'Large' }
|
|
],
|
|
value: selected,
|
|
onchange: (e) => selected(e.target.value)
|
|
}),
|
|
Div({ class: 'alert alert-info' }, [
|
|
`You selected: ${selected()}`
|
|
])
|
|
]);
|
|
};
|
|
$mount(ReactiveDemo, reactiveTarget);
|
|
}
|
|
|
|
// 3. Disabled State
|
|
const disabledTarget = document.querySelector('#demo-disabled');
|
|
if (disabledTarget && !disabledTarget.hasChildNodes()) {
|
|
const DisabledDemo = () => {
|
|
return Select({
|
|
label: 'Country (disabled)',
|
|
items: [
|
|
{ value: 'mx', label: 'Mexico' },
|
|
{ value: 'us', label: 'United States' },
|
|
{ value: 'ca', label: 'Canada' }
|
|
],
|
|
value: 'mx',
|
|
disabled: true
|
|
});
|
|
};
|
|
$mount(DisabledDemo, disabledTarget);
|
|
}
|
|
|
|
// 4. Dynamic items
|
|
const dynamicTarget = document.querySelector('#demo-dynamic');
|
|
if (dynamicTarget && !dynamicTarget.hasChildNodes()) {
|
|
const DynamicDemo = () => {
|
|
const category = $('fruits');
|
|
|
|
const items = {
|
|
fruits: [
|
|
{ value: 'apple', label: '🍎 Apple' },
|
|
{ value: 'banana', label: '🍌 Banana' }
|
|
],
|
|
vegetables: [
|
|
{ value: 'carrot', label: '🥕 Carrot' },
|
|
{ value: 'broccoli', label: '🥦 Broccoli' }
|
|
]
|
|
};
|
|
|
|
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
|
Select({
|
|
label: 'Category',
|
|
items: [
|
|
{ value: 'fruits', label: 'Fruits' },
|
|
{ value: 'vegetables', label: 'Vegetables' }
|
|
],
|
|
value: category,
|
|
onchange: (e) => category(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Item',
|
|
items: () => items[category()] || [],
|
|
value: $(''),
|
|
onchange: (e) => console.log('Selected:', e.target.value)
|
|
})
|
|
]);
|
|
};
|
|
$mount(DynamicDemo, dynamicTarget);
|
|
}
|
|
|
|
// 5. All Variants
|
|
const variantsTarget = document.querySelector('#demo-variants');
|
|
if (variantsTarget && !variantsTarget.hasChildNodes()) {
|
|
const VariantsDemo = () => {
|
|
const primary = $('option1');
|
|
const secondary = $('option2');
|
|
const accent = $('');
|
|
|
|
return Div({ class: 'flex flex-col gap-4' }, [
|
|
Select({
|
|
label: 'Primary Select',
|
|
class: 'select-primary',
|
|
items: [
|
|
{ value: 'option1', label: 'Option 1' },
|
|
{ value: 'option2', label: 'Option 2' },
|
|
{ value: 'option3', label: 'Option 3' }
|
|
],
|
|
value: primary,
|
|
onchange: (e) => primary(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Secondary Select',
|
|
class: 'select-secondary',
|
|
items: [
|
|
{ value: 'option1', label: 'Option 1' },
|
|
{ value: 'option2', label: 'Option 2' }
|
|
],
|
|
value: secondary,
|
|
onchange: (e) => secondary(e.target.value)
|
|
}),
|
|
Select({
|
|
label: 'Ghost Select',
|
|
class: 'select-ghost',
|
|
items: [
|
|
{ value: '', label: 'Select an option' },
|
|
{ value: 'opt1', label: 'Option 1' },
|
|
{ value: 'opt2', label: 'Option 2' }
|
|
],
|
|
value: accent,
|
|
onchange: (e) => accent(e.target.value)
|
|
})
|
|
]);
|
|
};
|
|
$mount(VariantsDemo, variantsTarget);
|
|
}
|
|
};
|
|
|
|
initSelectExamples();
|
|
|
|
if (window.$docsify) {
|
|
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
|
|
hook.doneEach(initSelectExamples);
|
|
});
|
|
}
|
|
})();
|
|
</script>
|