Files
api/unraid-ui/src/forms/Select.vue
Michael Datelle 711cc9ac92 feat: build out docker components (#1427)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced comprehensive, customizable Accordion, Dialog,
DropdownMenu, and Select UI components with enhanced prop-driven and
slot-based APIs.
* Added grouped exports for UI primitives, simplifying imports and
usage.
* Added new Storybook stories demonstrating varied usage scenarios for
Accordion, Dialog, DropdownMenu, and Select components.

* **Refactor**
* Replaced external UI dependencies with locally defined, typed
components for Accordion, Dialog, DropdownMenu, and Select.
* Streamlined component APIs by consolidating exports to main components
and type exports, removing subcomponent exports.
* Simplified dialog and dropdown menu implementations with explicit
props, events, and slots.
* Updated component styles and class bindings for improved appearance
and interaction.
* Refined select component into a fully featured, typed implementation
supporting grouping and multiple selection.
* Replaced custom dropdown menu implementation in user profile with the
new DropdownMenu component.
* Simplified internal prop forwarding using reactive utilities for
dropdown menu and select subcomponents.
* Improved dropdown menu stories with declarative props and slots,
removing manual subcomponent composition.
* Simplified notification filter UI by replacing nested select
subcomponents with a declarative items prop.

* **Bug Fixes**
* Improved dropdown and select item handling, including disabled states,
separators, and grouped options.

* **Style**
* Enhanced visual consistency and spacing in documentation and UI
components.
  * Updated component classes for better appearance and usability.

* **Chores**
* Upgraded `@jsonforms` dependencies across all packages to version
`^3.6.0`.
  * Improved test and mock setups for new component structures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2025-07-03 16:40:06 -04:00

78 lines
2.5 KiB
Vue

<script setup lang="ts">
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/common/tooltip';
import {
SelectContent,
SelectItem,
SelectItemText,
SelectRoot,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import useTeleport from '@/composables/useTeleport';
import type { ControlElement } from '@jsonforms/core';
import { useJsonFormsControl } from '@jsonforms/vue';
import type { RendererProps } from '@jsonforms/vue';
import { computed } from 'vue';
const props = defineProps<RendererProps<ControlElement>>();
const { control, handleChange } = useJsonFormsControl(props);
const selected = computed(() => control.value.data);
const options = computed(() => {
const enumValues: string[] = control.value.schema.enum || [];
const tooltips: string[] | undefined = control.value.uischema.options?.tooltips;
return enumValues.map((value, index) => ({
value,
label: value,
tooltip: tooltips && tooltips[index] ? tooltips[index] : undefined,
}));
});
const onChange = (value: unknown) => {
handleChange(control.value.path, String(value));
};
// Without this, the select dropdown will not be visible, unless it's already in a teleported context.
const { teleportTarget, determineTeleportTarget } = useTeleport();
const onSelectOpen = () => {
determineTeleportTarget();
};
</script>
<template>
<SelectRoot
v-model="selected"
:disabled="!control.enabled"
:required="control.required"
@update:model-value="onChange"
@update:open="onSelectOpen"
>
<SelectTrigger>
<SelectValue v-if="selected">{{ selected }}</SelectValue>
<span v-else>{{ control.schema.default ?? 'Select an option' }}</span>
</SelectTrigger>
<SelectContent :to="teleportTarget">
<template v-for="option in options" :key="option.value">
<TooltipProvider v-if="option.tooltip" :delay-duration="50">
<Tooltip>
<TooltipTrigger as-child>
<SelectItem :value="option.value">
<SelectItemText>{{ option.label }}</SelectItemText>
</SelectItem>
</TooltipTrigger>
<TooltipContent :to="teleportTarget" side="right" :side-offset="5">
<p class="max-w-xs">{{ option.tooltip }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<SelectItem v-else :value="option.value">
<SelectItemText>{{ option.label }}</SelectItemText>
</SelectItem>
</template>
</SelectContent>
</SelectRoot>
</template>