refactor: improve accessibility and i18n for search components
• Replace label with ariaLabel prop • Add searchPlaceholder support • Use i18n keys for messages • Improve aria-label attributes • Standardize noResultsMessage fallback
This commit is contained in:
parent
ed5911f656
commit
ad247f2fc1
4 changed files with 20 additions and 12 deletions
|
|
@ -185,9 +185,11 @@ const GraphLabels = () => {
|
||||||
renderOption={(item) => <div style={{ whiteSpace: 'pre' }}>{item}</div>}
|
renderOption={(item) => <div style={{ whiteSpace: 'pre' }}>{item}</div>}
|
||||||
getOptionValue={(item) => item}
|
getOptionValue={(item) => item}
|
||||||
getDisplayValue={(item) => <div style={{ whiteSpace: 'pre' }}>{item}</div>}
|
getDisplayValue={(item) => <div style={{ whiteSpace: 'pre' }}>{item}</div>}
|
||||||
notFound={<div className="py-6 text-center text-sm">No labels found</div>}
|
notFound={<div className="py-6 text-center text-sm">{t('graphPanel.graphLabels.noLabels')}</div>}
|
||||||
label={t('graphPanel.graphLabels.label')}
|
ariaLabel={t('graphPanel.graphLabels.label')}
|
||||||
placeholder={t('graphPanel.graphLabels.placeholder')}
|
placeholder={t('graphPanel.graphLabels.placeholder')}
|
||||||
|
searchPlaceholder={t('graphPanel.graphLabels.placeholder')}
|
||||||
|
noResultsMessage={t('graphPanel.graphLabels.noLabels')}
|
||||||
value={label !== null ? label : '*'}
|
value={label !== null ? label : '*'}
|
||||||
onChange={(newLabel) => {
|
onChange={(newLabel) => {
|
||||||
const currentLabel = useSettingsStore.getState().queryLabel;
|
const currentLabel = useSettingsStore.getState().queryLabel;
|
||||||
|
|
|
||||||
|
|
@ -215,8 +215,9 @@ export const GraphSearchInput = ({
|
||||||
onFocus={(id) => {
|
onFocus={(id) => {
|
||||||
if (id !== messageId && onFocus) onFocus(id ? { id, type: 'nodes' } : null)
|
if (id !== messageId && onFocus) onFocus(id ? { id, type: 'nodes' } : null)
|
||||||
}}
|
}}
|
||||||
label={'item'}
|
ariaLabel={t('graphPanel.search.placeholder')}
|
||||||
placeholder={t('graphPanel.search.placeholder')}
|
placeholder={t('graphPanel.search.placeholder')}
|
||||||
|
noResultsMessage={t('graphPanel.search.placeholder')}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ export interface AsyncSearchProps<T> {
|
||||||
onChange: (value: string) => void
|
onChange: (value: string) => void
|
||||||
/** Callback when focus changes */
|
/** Callback when focus changes */
|
||||||
onFocus: (value: string) => void
|
onFocus: (value: string) => void
|
||||||
/** Label for the select field */
|
/** Accessibility label for the search field */
|
||||||
label: string
|
ariaLabel?: string
|
||||||
/** Placeholder text when no selection */
|
/** Placeholder text when no selection */
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
/** Disable the entire select */
|
/** Disable the entire select */
|
||||||
|
|
@ -67,7 +67,7 @@ export function AsyncSearch<T>({
|
||||||
getOptionValue,
|
getOptionValue,
|
||||||
notFound,
|
notFound,
|
||||||
loadingSkeleton,
|
loadingSkeleton,
|
||||||
label,
|
ariaLabel,
|
||||||
placeholder = 'Select...',
|
placeholder = 'Select...',
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
|
@ -179,6 +179,7 @@ export function AsyncSearch<T>({
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
className="max-h-8"
|
className="max-h-8"
|
||||||
|
aria-label={ariaLabel}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSearchTerm(value)
|
setSearchTerm(value)
|
||||||
|
|
@ -198,7 +199,7 @@ export function AsyncSearch<T>({
|
||||||
!error &&
|
!error &&
|
||||||
options.length === 0 &&
|
options.length === 0 &&
|
||||||
(notFound || (
|
(notFound || (
|
||||||
<CommandEmpty>{noResultsMessage ?? `No ${label.toLowerCase()} found.`}</CommandEmpty>
|
<CommandEmpty>{noResultsMessage || 'No results found.'}</CommandEmpty>
|
||||||
))}
|
))}
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
{options.map((option, idx) => (
|
{options.map((option, idx) => (
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,12 @@ export interface AsyncSelectProps<T> {
|
||||||
value: string
|
value: string
|
||||||
/** Callback when selection changes */
|
/** Callback when selection changes */
|
||||||
onChange: (value: string) => void
|
onChange: (value: string) => void
|
||||||
/** Label for the select field */
|
/** Accessibility label for the select field */
|
||||||
label: string
|
ariaLabel?: string
|
||||||
/** Placeholder text when no selection */
|
/** Placeholder text when no selection */
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
/** Display text for search placeholder */
|
||||||
|
searchPlaceholder?: string
|
||||||
/** Disable the entire select */
|
/** Disable the entire select */
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
/** Custom width for the popover *
|
/** Custom width for the popover *
|
||||||
|
|
@ -76,8 +78,9 @@ export function AsyncSelect<T>({
|
||||||
getDisplayValue,
|
getDisplayValue,
|
||||||
notFound,
|
notFound,
|
||||||
loadingSkeleton,
|
loadingSkeleton,
|
||||||
label,
|
ariaLabel,
|
||||||
placeholder = 'Select...',
|
placeholder = 'Select...',
|
||||||
|
searchPlaceholder,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
|
@ -200,6 +203,7 @@ export function AsyncSelect<T>({
|
||||||
variant="outline"
|
variant="outline"
|
||||||
role="combobox"
|
role="combobox"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
|
aria-label={ariaLabel}
|
||||||
className={cn(
|
className={cn(
|
||||||
'justify-between',
|
'justify-between',
|
||||||
disabled && 'cursor-not-allowed opacity-50',
|
disabled && 'cursor-not-allowed opacity-50',
|
||||||
|
|
@ -223,7 +227,7 @@ export function AsyncSelect<T>({
|
||||||
<Command shouldFilter={false}>
|
<Command shouldFilter={false}>
|
||||||
<div className="relative w-full border-b">
|
<div className="relative w-full border-b">
|
||||||
<CommandInput
|
<CommandInput
|
||||||
placeholder={`Search ${label.toLowerCase()}...`}
|
placeholder={searchPlaceholder || 'Search...'}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSearchTerm(value)
|
setSearchTerm(value)
|
||||||
|
|
@ -244,7 +248,7 @@ export function AsyncSelect<T>({
|
||||||
options.length === 0 &&
|
options.length === 0 &&
|
||||||
(notFound || (
|
(notFound || (
|
||||||
<CommandEmpty>
|
<CommandEmpty>
|
||||||
{noResultsMessage ?? `No ${label.toLowerCase()} found.`}
|
{noResultsMessage || 'No results found.'}
|
||||||
</CommandEmpty>
|
</CommandEmpty>
|
||||||
))}
|
))}
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue