Skip to content

Commit

Permalink
fix(AutoComplete): customValue and returnObject compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
lukicenturi committed Sep 10, 2024
1 parent d06867b commit 9c1abe1
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 43 deletions.
95 changes: 72 additions & 23 deletions example/src/views/AutoCompleteView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,8 @@ const autoComplete = ref<RuiAutoCompleteProps[]>([
},
]);
const autoCompleteCustom = ref<RuiAutoCompleteProps[]>([
const autoCompleteCustom = ref<RuiAutoCompleteProps<number | SelectOption[]>[]>([
{
disabled: false,
keyAttr: 'id',
textAttr: 'label',
modelValue: undefined,
Expand All @@ -96,17 +95,18 @@ const autoCompleteCustom = ref<RuiAutoCompleteProps[]>([
keyAttr: 'id',
textAttr: 'label',
modelValue: undefined,
label: 'With error messages',
dense: true,
errorMessages: ['This is required'],
hint: 'lorem ipsum dolor',
options,
},
{
disabled: false,
label: 'primitive return',
variant: 'outlined',
keyAttr: 'id',
textAttr: 'label',
dense: true,
label: 'With success messages',
successMessages: ['lgtm!'],
modelValue: undefined,
options,
Expand All @@ -116,9 +116,52 @@ const autoCompleteCustom = ref<RuiAutoCompleteProps[]>([
variant: 'outlined',
keyAttr: 'id',
textAttr: 'label',
label: 'Disabled',
dense: true,
modelValue: undefined,
options,
},
{
variant: 'outlined',
textAttr: 'label',
keyAttr: 'id',
label: 'Multiple',
dense: true,
modelValue: [],
options,
},
{
variant: 'outlined',
textAttr: 'label',
label: 'Return Object',
dense: true,
modelValue: undefined,
returnObject: true,
options,
},
{
variant: 'outlined',
keyAttr: 'id',
textAttr: 'label',
label: 'Multiple and Return Object',
dense: true,
modelValue: [],
chips: true,
returnObject: true,
options,
},
{
variant: 'outlined',
keyAttr: 'id',
textAttr: 'label',
label: 'Multiple, Return Object, and Custom Value',
dense: true,
modelValue: [],
chips: true,
customValue: true,
returnObject: true,
options,
},
]);
const primitiveOptions: string[] = ['Lorem', 'Ipsum', 'Dolor', 'Sit amet', 'Consecteur'];
Expand Down Expand Up @@ -308,36 +351,41 @@ function getDisplayText(options?: SelectOption | SelectOption[]): string {
</div>
<h4
class="text-h6 mt-6"
data-cy="auto-completes-custom-inner"
data-cy="auto-completes-custom"
>
Auto Complete: custom activator inner content
Auto Complete: custom activator content
</h4>
<div class="grid gap-6 grid-cols-2">
<div
v-for="(autoCompleteProp, i) in autoCompleteCustom"
v-for="(item, i) in autoCompleteCustom"
:key="i"
class="py-4"
>
<RuiAutoComplete
v-model="autoCompleteProp.modelValue"
v-model="item.modelValue"
clearable
auto-select-first
v-bind="objectOmit(autoCompleteProp, ['modelValue'])"
:data-cy="`auto-complete-custom-inner-${i}`"
:item-height="autoCompleteProp.dense ? undefined : 80"
:label-class="autoCompleteProp.dense ? undefined : 'h-20'"
variant="outlined"
v-bind="objectOmit(item, ['modelValue'])"
:data-cy="`auto-complete-custom-${i}`"
>
<template #selection="{ item }">
{{ item.id }} | {{ item.label }}
</template>
<template #item="{ item }">
<span
class="block"
:class="{ 'my-4': !autoCompleteProp.dense }"
<template #activator="{ attrs, disabled, open, value }">
<RuiButton
class="!rounded-md border"
data-cy="activator"
variant="list"
:disabled="disabled"
v-bind="attrs"
>
{{ item.label }}
</span>
{{ getDisplayText(value) }}
<template #append>
<RuiIcon
class="transition"
:class="[{ 'rotate-180': open }]"
name="arrow-drop-down-fill"
size="32"
/>
</template>
</RuiButton>
</template>
</RuiAutoComplete>
</div>
Expand Down Expand Up @@ -404,7 +452,8 @@ function getDisplayText(options?: SelectOption | SelectOption[]): string {
</template>
</RuiAutoComplete>
</div>
</div><h4
</div>
<h4
class="text-h6 mt-6"
data-cy="auto-completes-readonly"
>
Expand Down
24 changes: 11 additions & 13 deletions src/components/forms/auto-complete/RuiAutoComplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const value = computed<TItem[]>({
if (inOptions)
return filtered.push(inOptions);
if (props.customValue)
return filtered.push(textValueToProperValue(val));
return filtered.push(textValueToProperValue(val, props.returnObject));
});
if (multiple || filtered.length === 0) {
Expand All @@ -208,7 +208,7 @@ const value = computed<TItem[]>({
if (inOptions)
return filtered.push(inOptions);
if (props.customValue)
return filtered.push(textValueToProperValue(val));
return filtered.push(textValueToProperValue(val, props.returnObject));
});
if (get(shouldApplyValueAsSearch) && !get(recentlyFocused)) {
Expand Down Expand Up @@ -340,10 +340,7 @@ watch(focusedValueIndex, async (index) => {
return;
await nextTick(() => {
const keyAttr = props.keyAttr;
const entry = get(value)[index];
const data = keyAttr ? entry[keyAttr] : entry;
const activeChip = get(activator).querySelector(`[data-value="${data}"]`);
const activeChip = get(activator).querySelector(`[data-index="${index}"]`);
activeChip?.focus();
});
});
Expand Down Expand Up @@ -382,10 +379,10 @@ const inputClass = computed<string>(() => {
return 'flex-1 min-w-0';
});
function textValueToProperValue(val: any): TItem {
function textValueToProperValue(val: any, returnObject: boolean = false): TItem {
const keyAttr = props.keyAttr;
const textAttr = props.textAttr;
if (!keyAttr)
if (!keyAttr || returnObject)
return val;
return {
Expand Down Expand Up @@ -449,6 +446,7 @@ function onInputDeletePressed(): void {
function chipAttrs(item: TItem, index: number) {
return {
'data-index': index,
'data-value': getIdentifier(item),
'onKeydown': (event: KeyboardEvent): void => {
const { key } = event;
Expand Down Expand Up @@ -710,20 +708,20 @@ defineExpose({
ref="menuRef"
>
<RuiButton
v-for="({ item, index }) in renderedData"
v-for="({ item, _index }) in renderedData"
ref="renderedOptions"
:key="getIdentifier(item)?.toString()"
:active="isActiveItem(item)"
:size="dense ? 'sm' : undefined"
tabindex="0"
variant="list"
:class="{
highlighted: highlightedIndex === index,
[css.highlighted]: highlightedIndex === index,
highlighted: highlightedIndex === _index,
[css.highlighted]: highlightedIndex === _index,
[css.active]: isActiveItem(item),
}"
@click="setValue(item, index)"
@mousedown="highlightedIndex = index"
@click="setValue(item, _index)"
@mousedown="highlightedIndex = _index"
>
<template #prepend>
<slot
Expand Down
12 changes: 6 additions & 6 deletions src/components/forms/select/RuiMenuSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,18 @@ function clear() {
ref="menuRef"
>
<RuiButton
v-for="({ item, index }) in renderedData"
:key="index"
v-for="({ item, _index }) in renderedData"
:key="_index"
:active="isActiveItem(item)"
:size="dense ? 'sm' : undefined"
:model-value="getIdentifier(item)"
variant="list"
:class="{
highlighted: highlightedIndex === index,
[css.highlighted]: !isActiveItem(item) && highlightedIndex === index,
highlighted: highlightedIndex === _index,
[css.highlighted]: !isActiveItem(item) && highlightedIndex === _index,
}"
@update:model-value="setValue(item, index)"
@mousedown="highlightedIndex = index"
@update:model-value="setValue(item, _index)"
@mousedown="highlightedIndex = _index"
>
<template #prepend>
<slot
Expand Down
2 changes: 1 addition & 1 deletion src/composables/dropdown-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function useDropdownMenu<TValue, TItem>({
},
);

const renderedData = useArrayMap(list, ({ data, index }) => ({ index, item: data }));
const renderedData = useArrayMap(list, ({ data, index: _index }) => ({ _index, item: data }));

const isOpen = ref(false);

Expand Down

0 comments on commit 9c1abe1

Please sign in to comment.