Skip to content

Commit

Permalink
pkp/pkp-lib#10624 Add ROR autosuggest component
Browse files Browse the repository at this point in the history
  • Loading branch information
blesildaramirez committed Dec 3, 2024
1 parent a49eace commit 0a82e70
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 68 deletions.
105 changes: 73 additions & 32 deletions src/components/Form/fields/Autosuggest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
>
<Icon icon="Cancel" class="h-3 w-3" />
<span class="-screenReader">
{{ deselectLabel.replace('{$item}', item.label) }}
{{ deselectLabel?.replace('{$item}', item.label) }}
</span>
</button>
</PkpBadge>
Expand All @@ -31,48 +31,72 @@
@update:model-value="selectSuggestion"
>
<ComboboxInput
ref="autosuggestInput"
class="pkpAutosuggest__input"
v-bind="inputProps"
autocomplete="off"
@change="(event) => handleChange(event)"
@focus="() => handleFocus()"
@blur="() => handleBlur()"
@focus="() => handleFocus(true)"
@blur="() => handleFocus(false)"
/>
<ComboboxOptions
v-if="suggestions.length || (allowCustom && localInputValue?.length)"
v-if="
suggestions.length ||
(allowCustom && localInputValue?.length) ||
isLoading
"
class="autosuggest__results-container autosuggest__results"
>
<ComboboxOption
v-if="
allowCustom &&
localInputValue?.length &&
!suggestions.includes(localInputValue)
"
v-if="isLoading"
v-slot="{active}"
as="template"
:disabled="true"
>
<li
class="autosuggest__results-item"
:class="active && 'autosuggest__results-item--highlighted'"
>
{{ localInputValue }}
<Spinner />
{{ t('common.loading') }}
</li>
</ComboboxOption>
<ComboboxOption
v-for="suggestion in suggestions"
:key="suggestion.value"
v-if="
allowCustom &&
localInputValue?.length &&
!suggestions.includes(localInputValue)
"
v-slot="{active}"
:value="suggestion"
as="template"
>
<li
class="autosuggest__results-item flex items-center"
class="autosuggest__results-item"
:class="active && 'autosuggest__results-item--highlighted'"
>
<slot v-if="slots['option']" name="option" :suggestion="suggestion" />
<span v-else>{{ suggestion.label }}</span>
{{ localInputValue }}
</li>
</ComboboxOption>
<template v-if="!isLoading">
<ComboboxOption
v-for="suggestion in suggestions"
:key="suggestion.value"
v-slot="{active}"
:value="suggestion"
as="template"
>
<li
class="autosuggest__results-item flex items-center"
:class="active && 'autosuggest__results-item--highlighted'"
>
<slot
v-if="slots['option']"
name="option"
:suggestion="suggestion"
/>
<span v-else>{{ suggestion.label }}</span>
</li>
</ComboboxOption>
</template>
</ComboboxOptions>
</Combobox>
</template>
Expand All @@ -86,6 +110,7 @@ import {
} from '@headlessui/vue';
import PkpBadge from '@/components/Badge/Badge.vue';
import Icon from '@/components/Icon/Icon.vue';
import Spinner from '@/components/Spinner/Spinner.vue';
const slots = useSlots();
Expand All @@ -94,10 +119,6 @@ const props = defineProps({
type: String,
required: true,
},
inputProps: {
type: Object,
required: true,
},
suggestions: {
type: Array,
default: () => [],
Expand All @@ -122,36 +143,54 @@ const props = defineProps({
type: String,
default: () => '',
},
isFocused: {
isLoading: {
type: Boolean,
default: () => false,
},
inputDescribedByIds: {
type: String,
required: true,
},
inputControlId: {
type: String,
required: true,
},
inputName: {
type: String,
default: () => 'autosuggest',
},
});
/**
* Props to pass to the input field
*/
const inputProps = {
'aria-describedby': props.inputDescribedByIds,
class: 'pkpAutosuggest__input',
id: props.inputControlId,
name: props.inputName,
disabled: props.isDisabled,
};
const emit = defineEmits([
'update:inputValue',
'update:isFocused',
'focus-changed',
'select-suggestion',
'deselect',
]);
const allowCustom = inject('allowCustom', false);
const localInputValue = ref('');
const localIsFocused = ref(props.isFocused);
const isFocused = ref(false);
function handleChange(event) {
localInputValue.value = event.target.value.trim();
emit('update:inputValue', localInputValue.value);
}
function handleFocus() {
localIsFocused.value = true;
emit('update:isFocused', localIsFocused.value);
}
function handleBlur() {
localIsFocused.value = false;
emit('update:isFocused', localIsFocused.value);
function handleFocus(state) {
isFocused.value = state;
emit('focus-changed', state);
}
function selectSuggestion(suggestion) {
Expand All @@ -161,4 +200,6 @@ function selectSuggestion(suggestion) {
function deselect(item) {
emit('deselect', item);
}
defineExpose({handleFocus});
</script>
4 changes: 2 additions & 2 deletions src/components/Form/fields/FieldBaseAutosuggest.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ const RORExample = {
);

const suggestions = items
.filter((u) => u.fullName.match(regex))
.filter((u) => u.name.match(regex))
.filter((u) => !this.currentValue.includes(u.id))
.map((u) => {
return {
value: u.id,
label: u.fullName,
label: u.name,
hasSlot: u.ror,
};
});
Expand Down
39 changes: 15 additions & 24 deletions src/components/Form/fields/FieldBaseAutosuggest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
:class="{
'pkpAutosuggest__inputWrapper--multilingual':
isMultilingual && locales.length > 1,
'pkpAutosuggest__inputWrapper--focus': isFocused,
'pkpAutosuggest__inputWrapper--focus': inputFocused,
}"
@click="setFocusToInput"
>
Expand Down Expand Up @@ -83,11 +83,11 @@
<Autosuggest
v-if="!isDisabled"
v-bind="autoSuggestProps"
ref="cb"
ref="inputRef"
v-model:inputValue="inputValue"
v-model:isFocused="isFocused"
@select-suggestion="selectSuggestion"
@deselect="deselect"
@focus-changed="changeFocus"
>
<template v-if="$slots['input-slot']" #input-slot>
<slot name="input-slot"></slot>
Expand Down Expand Up @@ -194,7 +194,7 @@ export default {
data() {
return {
inputValue: '',
isFocused: false,
inputFocused: false,
suggestions: [],
};
},
Expand Down Expand Up @@ -242,24 +242,6 @@ export default {
);
},
/**
* Props to pass to the input field
*
* @return {Object}
*/
inputProps() {
let props = {
'aria-describedby': this.describedByIds,
class: 'pkpAutosuggest__input',
id: this.controlId,
name: this.name,
};
if (this.isDisabled) {
props.disabled = 'disabled';
}
return props;
},
/**
* Is this field in a right-to-left language
*/
Expand All @@ -270,12 +252,14 @@ export default {
autoSuggestProps() {
return {
id: this.autosuggestId,
inputProps: this.inputProps,
suggestions: this.suggestions,
selectedLabel: this.selectedLabel,
currentSelected: this.currentSelected,
isDisabled: this.isDisabled,
deselectLabel: this.deselectLabel,
inputDescribedByIds: this.describedByIds,
inputControlId: this.controlId,
inputName: this.name,
};
},
},
Expand Down Expand Up @@ -319,7 +303,14 @@ export default {
return;
}
this.$refs.cb.$refs.autosuggestInput.$el.focus();
this.$refs.inputRef.handleFocus(true);
},
/**
* Change the input focus state
*/
changeFocus(state) {
this.inputFocused = state;
},
/**
Expand Down
24 changes: 24 additions & 0 deletions src/components/Form/fields/FieldRorAutosuggest.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import FieldRorAutosuggest from './FieldRorAutosuggest.vue';

export default {
title: 'Components/FieldRorAutosuggest',
component: FieldRorAutosuggest,
render: (args) => ({
components: {FieldRorAutosuggest},
setup() {
return {args};
},
template: '<FieldRorAutosuggest v-bind="args" />',
}),
};

export const Default = {
render: (args) => ({
components: {FieldRorAutosuggest},
setup() {
return {args};
},
template: '<FieldRorAutosuggest v-bind="args" />',
}),
args: {},
};
Loading

0 comments on commit 0a82e70

Please sign in to comment.