fix
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { EditIcon, IconX, PlusIcon } from '../ui/icons';
|
||||
import QuickAddMenu from '../ui/QuickAddMenu';
|
||||
import SelectionAssignmentMenu from './SelectionAssignmentMenu';
|
||||
import { getTagColorStyle } from '../utils/colors';
|
||||
import {
|
||||
formatDate,
|
||||
@@ -34,6 +34,29 @@ export const buildCorrespondentOptions = (entries = []) => {
|
||||
|
||||
const normalizeOptions = (options) => (Array.isArray(options) ? options : []);
|
||||
|
||||
const normalizeQuickAddOption = (option) => {
|
||||
if (option == null) {
|
||||
return null;
|
||||
}
|
||||
if (typeof option === 'string') {
|
||||
const label = option.trim();
|
||||
return label ? { id: label, label, original: option } : null;
|
||||
}
|
||||
const label = typeof option.label === 'string'
|
||||
? option.label.trim()
|
||||
: typeof option.name === 'string'
|
||||
? option.name.trim()
|
||||
: '';
|
||||
if (!label) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: option.id ?? label,
|
||||
label,
|
||||
original: option,
|
||||
};
|
||||
};
|
||||
|
||||
export const TagSection = ({
|
||||
tags = [],
|
||||
onRemove,
|
||||
@@ -63,10 +86,71 @@ export const TagSection = ({
|
||||
[onAdd],
|
||||
);
|
||||
|
||||
const normalizedOptions = useMemo(() => normalizeOptions(datalistOptions), [datalistOptions]);
|
||||
const normalizedOptions = useMemo(
|
||||
() =>
|
||||
normalizeOptions(datalistOptions)
|
||||
.map((option) => normalizeQuickAddOption(option))
|
||||
.filter(Boolean),
|
||||
[datalistOptions],
|
||||
);
|
||||
const containerClass = className ? `tag-list ${className}` : 'tag-list';
|
||||
const showQuickAdd = Boolean(onAdd);
|
||||
|
||||
const assignmentItems = useMemo(() => {
|
||||
const map = new Map();
|
||||
|
||||
normalizedOptions.forEach((option) => {
|
||||
const label = option?.label?.trim();
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
const key = label.toLowerCase();
|
||||
if (map.has(key)) {
|
||||
return;
|
||||
}
|
||||
map.set(key, {
|
||||
id: option.id ?? label,
|
||||
label,
|
||||
state: 'none',
|
||||
payload: option.original ?? { label },
|
||||
});
|
||||
});
|
||||
|
||||
tags.forEach((tag) => {
|
||||
const label = typeof tag?.label === 'string' ? tag.label.trim() : '';
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
const key = label.toLowerCase();
|
||||
const payload = { id: tag.id, label, color: tag.color ?? null };
|
||||
if (map.has(key)) {
|
||||
const entry = map.get(key);
|
||||
entry.state = 'all';
|
||||
entry.payload = payload;
|
||||
return;
|
||||
}
|
||||
map.set(key, {
|
||||
id: tag.id ?? label,
|
||||
label,
|
||||
state: 'all',
|
||||
payload,
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(map.values());
|
||||
}, [normalizedOptions, tags]);
|
||||
|
||||
const handleAssignmentSelect = useCallback(
|
||||
(item) => {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const payload = item.payload ?? { label: item.label };
|
||||
handleSelect(payload);
|
||||
},
|
||||
[handleSelect],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
{tags.map((tag) => {
|
||||
@@ -89,14 +173,17 @@ export const TagSection = ({
|
||||
);
|
||||
})}
|
||||
{showQuickAdd ? (
|
||||
<QuickAddMenu
|
||||
options={normalizedOptions}
|
||||
onCreate={handleCreate}
|
||||
onSelectOption={(original, normalized) => handleSelect(normalized || original)}
|
||||
<SelectionAssignmentMenu
|
||||
label="Add tag"
|
||||
items={assignmentItems}
|
||||
placeholder={addPlaceholder}
|
||||
emptyMessage="No tags"
|
||||
createLabel={addButtonLabel}
|
||||
triggerAriaLabel="Add tag"
|
||||
triggerTitle={addButtonLabel}
|
||||
onToggle={handleAssignmentSelect}
|
||||
onCreate={handleCreate}
|
||||
showStateIndicators
|
||||
showCounts={false}
|
||||
positionStrategy="fixed"
|
||||
triggerClassName="quick-add__chip quick-add__trigger"
|
||||
triggerContent={(
|
||||
<span className="quick-add__chip-label">
|
||||
@@ -125,31 +212,82 @@ export const CorrespondentSection = ({
|
||||
[onAdd],
|
||||
);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(original, normalized) => {
|
||||
if (!onAdd) return;
|
||||
const source = normalized && typeof normalized === 'object' ? normalized : original;
|
||||
const normalizedOptions = useMemo(
|
||||
() =>
|
||||
normalizeOptions(datalistOptions)
|
||||
.map((option) => normalizeQuickAddOption(option))
|
||||
.filter(Boolean),
|
||||
[datalistOptions],
|
||||
);
|
||||
const hasEntries = entries && entries.length > 0;
|
||||
const showQuickAdd = Boolean(onAdd);
|
||||
const containerClass = className ? `correspondent-list ${className}` : 'correspondent-list';
|
||||
|
||||
const assignmentItems = useMemo(() => {
|
||||
const map = new Map();
|
||||
|
||||
normalizedOptions.forEach((option) => {
|
||||
const label = option?.label?.trim();
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
const key = label.toLowerCase();
|
||||
if (map.has(key)) {
|
||||
return;
|
||||
}
|
||||
map.set(key, {
|
||||
id: option.id ?? label,
|
||||
label,
|
||||
state: 'none',
|
||||
payload: option.original ?? { name: label },
|
||||
});
|
||||
});
|
||||
|
||||
entries.forEach((entry) => {
|
||||
const label = typeof entry?.name === 'string' ? entry.name.trim() : '';
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
const key = label.toLowerCase();
|
||||
const payload = { id: entry.id, name: label };
|
||||
if (map.has(key)) {
|
||||
const item = map.get(key);
|
||||
item.state = 'all';
|
||||
item.payload = payload;
|
||||
return;
|
||||
}
|
||||
map.set(key, {
|
||||
id: entry.id ?? label,
|
||||
label,
|
||||
state: 'all',
|
||||
payload,
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(map.values());
|
||||
}, [normalizedOptions, entries]);
|
||||
|
||||
const handleAssignmentSelect = useCallback(
|
||||
(item) => {
|
||||
if (!onAdd || !item) {
|
||||
return;
|
||||
}
|
||||
const source = item.payload ?? item;
|
||||
const resolvedName =
|
||||
(source && typeof source.name === 'string' && source.name.trim()) ||
|
||||
(typeof source === 'string' ? source.trim() : '') ||
|
||||
(source && typeof source.label === 'string' ? source.label.trim() : '');
|
||||
(source && typeof source.name === 'string' && source.name.trim())
|
||||
|| (typeof source === 'string' ? source.trim() : '')
|
||||
|| (source && typeof source.label === 'string' ? source.label.trim() : '');
|
||||
if (!resolvedName) {
|
||||
return;
|
||||
}
|
||||
const payload =
|
||||
source && typeof source === 'object'
|
||||
? { ...source, name: resolvedName }
|
||||
: { id: null, name: resolvedName };
|
||||
const payload = typeof source === 'object'
|
||||
? { ...source, name: resolvedName }
|
||||
: { id: null, name: resolvedName };
|
||||
onAdd({ name: resolvedName, option: payload, input: null });
|
||||
},
|
||||
[onAdd],
|
||||
);
|
||||
|
||||
const normalizedOptions = useMemo(() => normalizeOptions(datalistOptions), [datalistOptions]);
|
||||
const hasEntries = entries && entries.length > 0;
|
||||
const showQuickAdd = Boolean(onAdd);
|
||||
const containerClass = className ? `correspondent-list ${className}` : 'correspondent-list';
|
||||
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
{hasEntries
|
||||
@@ -176,14 +314,17 @@ export const CorrespondentSection = ({
|
||||
})
|
||||
: !showQuickAdd && <span className="meta">No correspondents yet.</span>}
|
||||
{showQuickAdd ? (
|
||||
<QuickAddMenu
|
||||
options={normalizedOptions}
|
||||
onCreate={handleCreate}
|
||||
onSelectOption={(original, normalized) => handleSelect(original, normalized)}
|
||||
<SelectionAssignmentMenu
|
||||
label="Add correspondent"
|
||||
items={assignmentItems}
|
||||
placeholder={addPlaceholder}
|
||||
emptyMessage="No correspondents"
|
||||
createLabel={addButtonLabel}
|
||||
triggerAriaLabel="Add correspondent"
|
||||
triggerTitle={addButtonLabel}
|
||||
onToggle={handleAssignmentSelect}
|
||||
onCreate={handleCreate}
|
||||
showStateIndicators
|
||||
showCounts={false}
|
||||
positionStrategy="fixed"
|
||||
triggerClassName="quick-add__chip quick-add__trigger"
|
||||
triggerContent={(
|
||||
<span className="quick-add__chip-label">
|
||||
|
||||
@@ -31,10 +31,12 @@ const SelectionAssignmentMenu = ({
|
||||
disabled = false,
|
||||
className,
|
||||
triggerContent = null,
|
||||
triggerClassName = 'quick-add__chip quick-add__trigger panel-floating-actions__trigger',
|
||||
showStateIndicators = true,
|
||||
showCounts = true,
|
||||
onOpenMenu = null,
|
||||
renderItemLabel = null,
|
||||
positionStrategy = 'absolute',
|
||||
}) => {
|
||||
const anchorRef = useRef(null);
|
||||
const inputRef = useRef(null);
|
||||
@@ -51,7 +53,7 @@ const SelectionAssignmentMenu = ({
|
||||
} = useFloatingMenu({
|
||||
anchorRef,
|
||||
align: 'center',
|
||||
positionStrategy: 'absolute',
|
||||
positionStrategy,
|
||||
minWidth: 220,
|
||||
});
|
||||
|
||||
@@ -163,7 +165,7 @@ const SelectionAssignmentMenu = ({
|
||||
<button
|
||||
type="button"
|
||||
ref={anchorRef}
|
||||
className="quick-add__chip quick-add__trigger panel-floating-actions__trigger"
|
||||
className={triggerClassName}
|
||||
onClick={handleTriggerClick}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={isOpen}
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
box-shadow: 0 12px 28px var(--shadow-strong);
|
||||
min-width: 220px;
|
||||
z-index: 2500000;
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.menu[data-floating-position] {
|
||||
|
||||
Reference in New Issue
Block a user