-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #69 from TC4Y-777/dev
Use New Search Box
- Loading branch information
Showing
32 changed files
with
3,670 additions
and
341 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
728 changes: 728 additions & 0 deletions
728
Tithe-Vue/src/components/MultiSelectBox/Multiselect.vue
Large diffs are not rendered by default.
Oops, something went wrong.
182 changes: 182 additions & 0 deletions
182
Tithe-Vue/src/components/MultiSelectBox/composables/useA11y.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import { toRefs, onMounted, ref, computed } from 'vue' | ||
|
||
export default function useA11y (props, context, dep) | ||
{ | ||
const { | ||
placeholder, id, valueProp, label: labelProp, mode, groupLabel, aria, searchable , | ||
} = toRefs(props) | ||
|
||
// ============ DEPENDENCIES ============ | ||
|
||
const pointer = dep.pointer | ||
const iv = dep.iv | ||
const hasSelected = dep.hasSelected | ||
const multipleLabelText = dep.multipleLabelText | ||
|
||
// ================ DATA ================ | ||
|
||
const label = ref(null) | ||
|
||
// ============== COMPUTED ============== | ||
|
||
const ariaAssist = computed(() => { | ||
let texts = [] | ||
|
||
if (id && id.value) { | ||
texts.push(id.value) | ||
} | ||
|
||
texts.push('assist') | ||
|
||
return texts.join('-') | ||
}) | ||
|
||
const ariaControls = computed(() => { | ||
let texts = [] | ||
|
||
if (id && id.value) { | ||
texts.push(id.value) | ||
} | ||
|
||
texts.push('multiselect-options') | ||
|
||
return texts.join('-') | ||
}) | ||
|
||
const ariaActiveDescendant = computed(() => { | ||
let texts = [] | ||
|
||
if (id && id.value) { | ||
texts.push(id.value) | ||
} | ||
|
||
if (pointer.value) { | ||
texts.push(pointer.value.group ? 'multiselect-group' : 'multiselect-option') | ||
|
||
texts.push(pointer.value.group ? pointer.value.index : pointer.value[valueProp.value]) | ||
|
||
return texts.join('-') | ||
} | ||
}) | ||
|
||
|
||
|
||
const ariaPlaceholder = computed(() => { | ||
return placeholder.value | ||
}) | ||
|
||
const ariaMultiselectable = computed(() => { | ||
return mode.value !== 'single' | ||
}) | ||
|
||
const ariaLabel = computed(() => { | ||
let ariaLabel = '' | ||
|
||
if (mode.value === 'single' && hasSelected.value) { | ||
ariaLabel += iv.value[labelProp.value] | ||
} | ||
|
||
if (mode.value === 'multiple' && hasSelected.value) { | ||
ariaLabel += multipleLabelText.value | ||
} | ||
|
||
if (mode.value === 'tags' && hasSelected.value) { | ||
ariaLabel += iv.value.map(v => v[labelProp.value]).join(', ') | ||
} | ||
|
||
return ariaLabel | ||
}) | ||
|
||
const arias = computed(() => { | ||
let arias = { ...aria.value } | ||
|
||
// Need to add manually because focusing | ||
// the input won't read the selected value | ||
if (searchable.value) { | ||
arias['aria-labelledby'] = arias['aria-labelledby'] | ||
? `${ariaAssist.value} ${arias['aria-labelledby']}` | ||
: ariaAssist.value | ||
|
||
if (ariaLabel.value && arias['aria-label']) { | ||
arias['aria-label'] = `${ariaLabel.value}, ${arias['aria-label']}` | ||
} | ||
} | ||
|
||
return arias | ||
}) | ||
|
||
// =============== METHODS ============== | ||
|
||
const ariaOptionId = (option) => { | ||
let texts = [] | ||
|
||
if (id && id.value) { | ||
texts.push(id.value) | ||
} | ||
|
||
texts.push('multiselect-option') | ||
|
||
texts.push(option[valueProp.value]) | ||
|
||
return texts.join('-') | ||
} | ||
|
||
const ariaGroupId = (option) => { | ||
let texts = [] | ||
|
||
if (id && id.value) { | ||
texts.push(id.value) | ||
} | ||
|
||
texts.push('multiselect-group') | ||
|
||
texts.push(option.index) | ||
|
||
return texts.join('-') | ||
} | ||
|
||
const ariaOptionLabel = (label) => { | ||
let texts = [] | ||
|
||
texts.push(label) | ||
|
||
return texts.join(' ') | ||
} | ||
|
||
const ariaGroupLabel = (label) => { | ||
let texts = [] | ||
|
||
texts.push(label) | ||
|
||
return texts.join(' ') | ||
} | ||
|
||
const ariaTagLabel = (label) => { | ||
return `${label} ❎` | ||
} | ||
|
||
// =============== HOOKS ================ | ||
|
||
onMounted(() => { | ||
/* istanbul ignore next */ | ||
if (id && id.value && document && document.querySelector) { | ||
let forTag = document.querySelector(`[for="${id.value}"]`) | ||
label.value = forTag ? forTag.innerText : null | ||
} | ||
}) | ||
|
||
return { | ||
arias, | ||
ariaLabel, | ||
ariaAssist, | ||
ariaControls, | ||
ariaPlaceholder, | ||
ariaMultiselectable, | ||
ariaActiveDescendant, | ||
ariaOptionId, | ||
ariaOptionLabel, | ||
ariaGroupId, | ||
ariaGroupLabel, | ||
ariaTagLabel, | ||
} | ||
} |
160 changes: 160 additions & 0 deletions
160
Tithe-Vue/src/components/MultiSelectBox/composables/useClasses.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import { computed, toRefs } from 'vue' | ||
|
||
export default function useClasses (props, context, dependencies) | ||
{const { | ||
classes: classes_, disabled, openDirection, showOptions | ||
} = toRefs(props) | ||
|
||
// ============ DEPENDENCIES ============ | ||
|
||
const isOpen = dependencies.isOpen | ||
const isPointed = dependencies.isPointed | ||
const isSelected = dependencies.isSelected | ||
const isDisabled = dependencies.isDisabled | ||
const isActive = dependencies.isActive | ||
const canPointGroups = dependencies.canPointGroups | ||
const resolving = dependencies.resolving | ||
const fo = dependencies.fo | ||
|
||
const classes = computed(() => ({ | ||
container: 'multiselect', | ||
containerDisabled: 'is-disabled', | ||
containerOpen: 'is-open', | ||
containerOpenTop: 'is-open-top', | ||
containerActive: 'is-active', | ||
wrapper: 'multiselect-wrapper', | ||
singleLabel: 'multiselect-single-label', | ||
singleLabelText: 'multiselect-single-label-text', | ||
multipleLabel: 'multiselect-multiple-label', | ||
search: 'multiselect-search', | ||
tags: 'multiselect-tags', | ||
tag: 'multiselect-tag', | ||
tagDisabled: 'is-disabled', | ||
tagRemove: 'multiselect-tag-remove', | ||
tagRemoveIcon: 'multiselect-tag-remove-icon', | ||
tagsSearchWrapper: 'multiselect-tags-search-wrapper', | ||
tagsSearch: 'multiselect-tags-search', | ||
tagsSearchCopy: 'multiselect-tags-search-copy', | ||
placeholder: 'multiselect-placeholder', | ||
caret: 'multiselect-caret', | ||
caretOpen: 'is-open', | ||
clear: 'multiselect-clear', | ||
clearIcon: 'multiselect-clear-icon', | ||
spinner: 'multiselect-spinner', | ||
inifinite: 'multiselect-inifite', | ||
inifiniteSpinner: 'multiselect-inifite-spinner', | ||
dropdown: 'multiselect-dropdown', | ||
dropdownTop: 'is-top', | ||
dropdownHidden: 'is-hidden', | ||
options: 'multiselect-options', | ||
optionsTop: 'is-top', | ||
group: 'multiselect-group', | ||
groupLabel: 'multiselect-group-label', | ||
groupLabelPointable: 'is-pointable', | ||
groupLabelPointed: 'is-pointed', | ||
groupLabelSelected: 'is-selected', | ||
groupLabelDisabled: 'is-disabled', | ||
groupLabelSelectedPointed: 'is-selected is-pointed', | ||
groupLabelSelectedDisabled: 'is-selected is-disabled', | ||
groupOptions: 'multiselect-group-options', | ||
option: 'multiselect-option', | ||
optionPointed: 'is-pointed', | ||
optionSelected: 'is-selected', | ||
optionDisabled: 'is-disabled', | ||
optionSelectedPointed: 'is-selected is-pointed', | ||
optionSelectedDisabled: 'is-selected is-disabled', | ||
noOptions: 'multiselect-no-options', | ||
noResults: 'multiselect-no-results', | ||
fakeInput: 'multiselect-fake-input', | ||
assist: 'multiselect-assistive-text', | ||
spacer: 'multiselect-spacer', | ||
...classes_.value, | ||
})) | ||
|
||
// ============== COMPUTED ============== | ||
|
||
const showDropdown = computed(() => { | ||
return !!(isOpen.value && showOptions.value && (!resolving.value || (resolving.value && fo.value.length))) | ||
}) | ||
|
||
const classList = computed(() => { | ||
const c = classes.value | ||
|
||
return { | ||
container: [c.container] | ||
.concat(disabled.value ? c.containerDisabled : []) | ||
.concat(showDropdown.value && openDirection.value === 'top' ? c.containerOpenTop : []) | ||
.concat(showDropdown.value && openDirection.value !== 'top' ? c.containerOpen : []) | ||
.concat(isActive.value ? c.containerActive : []), | ||
wrapper: c.wrapper, | ||
spacer: c.spacer, | ||
singleLabel: c.singleLabel, | ||
singleLabelText: c.singleLabelText, | ||
multipleLabel: c.multipleLabel, | ||
search: c.search, | ||
tags: c.tags, | ||
tag: [c.tag] | ||
.concat(disabled.value ? c.tagDisabled : []), | ||
tagDisabled: c.tagDisabled, | ||
tagRemove: c.tagRemove, | ||
tagRemoveIcon: c.tagRemoveIcon, | ||
tagsSearchWrapper: c.tagsSearchWrapper, | ||
tagsSearch: c.tagsSearch, | ||
tagsSearchCopy: c.tagsSearchCopy, | ||
placeholder: c.placeholder, | ||
caret: [c.caret] | ||
.concat(isOpen.value ? c.caretOpen : []), | ||
clear: c.clear, | ||
clearIcon: c.clearIcon, | ||
spinner: c.spinner, | ||
inifinite: c.inifinite, | ||
inifiniteSpinner: c.inifiniteSpinner, | ||
dropdown: [c.dropdown] | ||
.concat(openDirection.value === 'top' ? c.dropdownTop : []) | ||
.concat(!isOpen.value || !showOptions.value || !showDropdown.value ? c.dropdownHidden : []), | ||
options: [c.options] | ||
.concat(openDirection.value === 'top' ? c.optionsTop : []), | ||
group: c.group, | ||
groupLabel: (g) => { | ||
let groupLabel = [c.groupLabel] | ||
|
||
if (isPointed(g)) { | ||
groupLabel.push(isSelected(g) ? c.groupLabelSelectedPointed : c.groupLabelPointed) | ||
} else if (isSelected(g) && canPointGroups.value) { | ||
groupLabel.push(isDisabled(g) ? c.groupLabelSelectedDisabled : c.groupLabelSelected) | ||
} else if (isDisabled(g)) { | ||
groupLabel.push(c.groupLabelDisabled) | ||
} | ||
|
||
if (canPointGroups.value) { | ||
groupLabel.push(c.groupLabelPointable) | ||
} | ||
|
||
return groupLabel | ||
}, | ||
groupOptions: c.groupOptions, | ||
option: (o, g) => { | ||
let option = [c.option] | ||
|
||
if (isPointed(o)) { | ||
option.push(isSelected(o) ? c.optionSelectedPointed : c.optionPointed) | ||
} else if (isSelected(o)) { | ||
option.push(isDisabled(o) ? c.optionSelectedDisabled : c.optionSelected) | ||
} else if (isDisabled(o) || (g && isDisabled(g))) { | ||
option.push(c.optionDisabled) | ||
} | ||
|
||
return option | ||
}, | ||
noOptions: c.noOptions, | ||
noResults: c.noResults, | ||
assist: c.assist, | ||
fakeInput: c.fakeInput, | ||
} | ||
}) | ||
|
||
return { | ||
classList, | ||
showDropdown, | ||
} | ||
} |
Oops, something went wrong.