Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type NonConfigurableComponentName = 'FoAvatarGroup'
| 'FoLoadingButton'
| 'FoMenuItem'
| 'FoModalTitle'
| 'FoMultipleSelect'
| 'FoPagination'
| 'FoPopover'
| 'FoSkeleton'
Expand Down
15 changes: 14 additions & 1 deletion packages/core/src/UI/Forms/Select/Types/Select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface BaseSelectProps<
Validity,
WithConfigurableHelperText {
/**
* The component's options.
* The select's options.
* An array where each option is an object that contains at least "id" and "text".
* In case of optgroup the array must contain an object with "options" and an optional "label"
*/
Expand All @@ -53,3 +53,16 @@ export type DatalistProps<
> = BaseSelectProps<T, K, K>
& WithPlaceholder
& WithLabel;

export interface MultipleSelectProps<
T extends string | number,
> extends MaybeStringId, Disableable, WithLabel {
/**
* The multiple select's options.
* An array where each option is an object that contains at least "id" and "text".
*/
options: SelectOption<T>[];

/** The number of options that are visible in the select without scrolling. */
visibleOptions?: number;
}
37 changes: 37 additions & 0 deletions packages/core/src/UI/Forms/Select/UI/FoMultipleSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<div>
<FoLabel v-if="label !== undefined"
:for="id"
>
{{ label }}
</FoLabel>

<select :id="id"
v-model="selectedOptions"
class="select h-auto"
:size="visibleOptions"
:disabled="isDisabled"
multiple
>
<FoSelectOption v-for="option in options"
:key="option.id"
:option="option"
/>
</select>
</div>
</template>

<script setup lang="ts" generic="T extends string | number">
import type { MultipleSelectProps, SelectOption } from '@/UI/Forms';
import { useElementId } from '@/Lib/UseIdentifiable/Internal';
import { FoLabel } from '@/UI/Components/Label/Internal';
import { FoSelectOption } from '@/UI/Forms/Select/Internal';

const props = withDefaults(defineProps<MultipleSelectProps<T>>(), {
visibleOptions: 4,
});

const selectedOptions = defineModel<SelectOption<T>[]>({ required: true });

const id = useElementId(() => props.id);
</script>
8 changes: 4 additions & 4 deletions packages/core/src/UI/Forms/Select/UI/FoSelect.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<template>
<!-- todo: multiple options -->
<div v-if="options.length"
:class="[
icon && useIcon && 'select',
Expand Down Expand Up @@ -83,24 +82,25 @@ import type { LabelType } from '@/UI/Components';
import type { SelectOption, SelectProps } from '@/UI/Forms';
import { useFlyonUIVueAppConfig } from '@/Lib';
import { useFloatingLabel } from '@/Lib/UseFloatingLabel/Internal';
import { useElementId } from '@/Lib/UseIdentifiable/Internal';
import { useShape } from '@/Lib/UseShape/Internal';
import { useSize } from '@/Lib/UseSize/Internal';

import { useSize } from '@/Lib/UseSize/Internal';
import { useValidity } from '@/Lib/UseValidity/Internal';
import { FoHelperText, usePositionableHelperText } from '@/UI/Components/HelperText/Internal';
import { FoLabel, useLabel } from '@/UI/Components/Label/Internal';
import { FoIcon } from '@/UI/Customization';
import { isSelectOptionGroup } from '@/UI/Forms/Select/Internal';
import { onEmptyOptions } from '@/UI/Forms/Select/Internal/Lib/OnEmptyOptions';
import FoSelectOption from '@/UI/Forms/Select/Internal/UI/FoSelectOption.vue';
import { computed, useId, watchEffect } from 'vue';
import { computed, watchEffect } from 'vue';

const props = withDefaults(defineProps<SelectProps<T, K>>(), {
isDisabled: undefined,
isValid: undefined,
});

const id = useId();
const id = useElementId(() => props.id);

const selectedOption = defineModel<SelectOption<T> | null>({ required: true });

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/UI/Forms/Select/UI/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as FoDatalist } from '@/UI/Forms/Select/UI/FoDatalist.vue';
export { default as FoMultipleSelect } from '@/UI/Forms/Select/UI/FoMultipleSelect.vue';
export { default as FoSelect } from '@/UI/Forms/Select/UI/FoSelect.vue';
4 changes: 4 additions & 0 deletions packages/docs/Forms/Select.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ When the input field is empty the selected option will automatically be null.

<SelectDocs section="datalist" />

### Multiple (Unreleased)

<SelectDocs section="multiple" />

### Optgroup

<SelectDocs section="optgroup" />
Expand Down
24 changes: 24 additions & 0 deletions packages/docs/Forms/Select/MultipleSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<FoMultipleSelect v-model="selectedOptions"
class="max-w-sm"
label="Pick your favorite Movies:"
:options="options"
:visible-options="3"
/>
</template>

<script setup lang="ts">
import type { SelectOption } from 'flyonui-vue';
import { FoMultipleSelect } from 'flyonui-vue';
import { ref } from 'vue';

const options = ref<SelectOption[]>([
{ id: 1, text: 'The Godfather' },
{ id: 2, text: 'The Shawshank Redemption' },
{ id: 3, text: 'Pulp Fiction' },
{ id: 4, text: 'The Dark Knight' },
{ id: 5, text: `Schindler's List` },
]);

const selectedOptions = ref<SelectOption[]>([]);
</script>
12 changes: 11 additions & 1 deletion packages/docs/Forms/Select/SelectDocs.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<ComponentDocs :previews="previews"
:section="section"
:api-docs-component-names="['FoSelect', 'FoDatalist']"
:api-docs-component-names="['FoSelect', 'FoMultipleSelect', 'FoDatalist']"
/>
</template>

Expand All @@ -16,6 +16,8 @@ import DefaultSelectSize from '@/Forms/Select/DefaultSelectSize.vu
import DefaultSelectSizeRaw from '@/Forms/Select/DefaultSelectSize.vue?raw';
import DisabledSelect from '@/Forms/Select/DisabledSelect.vue';
import DisabledSelectRaw from '@/Forms/Select/DisabledSelect.vue?raw';
import MultipleSelect from '@/Forms/Select/MultipleSelect.vue';
import MultipleSelectRaw from '@/Forms/Select/MultipleSelect.vue?raw';
import SelectAsDatalist from '@/Forms/Select/SelectAsDatalist.vue';
import SelectAsDatalistRaw from '@/Forms/Select/SelectAsDatalist.vue?raw';
import SelectFloatingLabel from '@/Forms/Select/SelectFloatingLabel.vue';
Expand Down Expand Up @@ -49,6 +51,7 @@ type Section = Default
| 'hidden-label'
| 'disabled'
| 'datalist'
| 'multiple'
| 'optgroup'
| 'ref-usage'
| ApiType;
Expand Down Expand Up @@ -146,6 +149,13 @@ const previews = computed(() => {
component: SelectAsDatalist,
},
],
[
'multiple',
{
code: MultipleSelectRaw,
component: MultipleSelect,
},
],
[
'optgroup',
{
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.