Merge remote-tracking branch 'ui/ui' into dev
This commit is contained in:
@@ -84,12 +84,13 @@ const createDesktopSurface = ({
|
|||||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||||
const detail = detailOpen && detailProps
|
const detail = detailOpen && detailProps
|
||||||
? (() => {
|
? (() => {
|
||||||
const { onClose, onOpenPreview, ...restDetailProps } = detailProps;
|
const { onClose, onOpenPreview, tags: tagOptions, ...restDetailProps } = detailProps;
|
||||||
return (
|
return (
|
||||||
<DocumentViewerPanel
|
<DocumentViewerPanel
|
||||||
variant="sidebar"
|
variant="sidebar"
|
||||||
onCollapsePanel={onClose}
|
onCollapsePanel={onClose}
|
||||||
onMaximizePanel={onOpenPreview}
|
onMaximizePanel={onOpenPreview}
|
||||||
|
tagOptions={tagOptions}
|
||||||
{...restDetailProps}
|
{...restDetailProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { EditIcon, IconX, PlusIcon } from '../ui/icons';
|
import { EditIcon, IconX, PlusIcon } from '../ui/icons';
|
||||||
import QuickAddMenu from '../ui/QuickAddMenu';
|
import SelectionAssignmentMenu from './SelectionAssignmentMenu';
|
||||||
import { getTagColorStyle } from '../utils/colors';
|
import { getTagColorStyle } from '../utils/colors';
|
||||||
import {
|
import {
|
||||||
formatDate,
|
formatDate,
|
||||||
@@ -34,6 +34,29 @@ export const buildCorrespondentOptions = (entries = []) => {
|
|||||||
|
|
||||||
const normalizeOptions = (options) => (Array.isArray(options) ? options : []);
|
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 = ({
|
export const TagSection = ({
|
||||||
tags = [],
|
tags = [],
|
||||||
onRemove,
|
onRemove,
|
||||||
@@ -63,10 +86,71 @@ export const TagSection = ({
|
|||||||
[onAdd],
|
[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 containerClass = className ? `tag-list ${className}` : 'tag-list';
|
||||||
const showQuickAdd = Boolean(onAdd);
|
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 (
|
return (
|
||||||
<div className={containerClass}>
|
<div className={containerClass}>
|
||||||
{tags.map((tag) => {
|
{tags.map((tag) => {
|
||||||
@@ -89,14 +173,17 @@ export const TagSection = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{showQuickAdd ? (
|
{showQuickAdd ? (
|
||||||
<QuickAddMenu
|
<SelectionAssignmentMenu
|
||||||
options={normalizedOptions}
|
label="Add tag"
|
||||||
onCreate={handleCreate}
|
items={assignmentItems}
|
||||||
onSelectOption={(original, normalized) => handleSelect(normalized || original)}
|
|
||||||
placeholder={addPlaceholder}
|
placeholder={addPlaceholder}
|
||||||
|
emptyMessage="No tags"
|
||||||
createLabel={addButtonLabel}
|
createLabel={addButtonLabel}
|
||||||
triggerAriaLabel="Add tag"
|
onToggle={handleAssignmentSelect}
|
||||||
triggerTitle={addButtonLabel}
|
onCreate={handleCreate}
|
||||||
|
showStateIndicators
|
||||||
|
showCounts={false}
|
||||||
|
positionStrategy="fixed"
|
||||||
triggerClassName="quick-add__chip quick-add__trigger"
|
triggerClassName="quick-add__chip quick-add__trigger"
|
||||||
triggerContent={(
|
triggerContent={(
|
||||||
<span className="quick-add__chip-label">
|
<span className="quick-add__chip-label">
|
||||||
@@ -125,19 +212,75 @@ export const CorrespondentSection = ({
|
|||||||
[onAdd],
|
[onAdd],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSelect = useCallback(
|
const normalizedOptions = useMemo(
|
||||||
(original, normalized) => {
|
() =>
|
||||||
if (!onAdd) return;
|
normalizeOptions(datalistOptions)
|
||||||
const source = normalized && typeof normalized === 'object' ? normalized : original;
|
.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 =
|
const resolvedName =
|
||||||
(source && typeof source.name === 'string' && source.name.trim()) ||
|
(source && typeof source.name === 'string' && source.name.trim())
|
||||||
(typeof source === 'string' ? source.trim() : '') ||
|
|| (typeof source === 'string' ? source.trim() : '')
|
||||||
(source && typeof source.label === 'string' ? source.label.trim() : '');
|
|| (source && typeof source.label === 'string' ? source.label.trim() : '');
|
||||||
if (!resolvedName) {
|
if (!resolvedName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const payload =
|
const payload = typeof source === 'object'
|
||||||
source && typeof source === 'object'
|
|
||||||
? { ...source, name: resolvedName }
|
? { ...source, name: resolvedName }
|
||||||
: { id: null, name: resolvedName };
|
: { id: null, name: resolvedName };
|
||||||
onAdd({ name: resolvedName, option: payload, input: null });
|
onAdd({ name: resolvedName, option: payload, input: null });
|
||||||
@@ -145,11 +288,6 @@ export const CorrespondentSection = ({
|
|||||||
[onAdd],
|
[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 (
|
return (
|
||||||
<div className={containerClass}>
|
<div className={containerClass}>
|
||||||
{hasEntries
|
{hasEntries
|
||||||
@@ -176,14 +314,17 @@ export const CorrespondentSection = ({
|
|||||||
})
|
})
|
||||||
: !showQuickAdd && <span className="meta">No correspondents yet.</span>}
|
: !showQuickAdd && <span className="meta">No correspondents yet.</span>}
|
||||||
{showQuickAdd ? (
|
{showQuickAdd ? (
|
||||||
<QuickAddMenu
|
<SelectionAssignmentMenu
|
||||||
options={normalizedOptions}
|
label="Add correspondent"
|
||||||
onCreate={handleCreate}
|
items={assignmentItems}
|
||||||
onSelectOption={(original, normalized) => handleSelect(original, normalized)}
|
|
||||||
placeholder={addPlaceholder}
|
placeholder={addPlaceholder}
|
||||||
|
emptyMessage="No correspondents"
|
||||||
createLabel={addButtonLabel}
|
createLabel={addButtonLabel}
|
||||||
triggerAriaLabel="Add correspondent"
|
onToggle={handleAssignmentSelect}
|
||||||
triggerTitle={addButtonLabel}
|
onCreate={handleCreate}
|
||||||
|
showStateIndicators
|
||||||
|
showCounts={false}
|
||||||
|
positionStrategy="fixed"
|
||||||
triggerClassName="quick-add__chip quick-add__trigger"
|
triggerClassName="quick-add__chip quick-add__trigger"
|
||||||
triggerContent={(
|
triggerContent={(
|
||||||
<span className="quick-add__chip-label">
|
<span className="quick-add__chip-label">
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import useFloatingMenu from '../ui/useFloatingMenu';
|
import useFloatingMenu from '../ui/useFloatingMenu';
|
||||||
import {
|
import { CheckIcon, CircleDashedCheckIcon, PlusIcon } from '../ui/icons';
|
||||||
PlusIcon,
|
|
||||||
CheckIcon,
|
|
||||||
CircleDashedCheckIcon,
|
|
||||||
} from '../ui/icons';
|
|
||||||
|
|
||||||
const STATE_ORDER = {
|
const STATE_ORDER = {
|
||||||
all: 0,
|
all: 0,
|
||||||
@@ -35,10 +31,12 @@ const SelectionAssignmentMenu = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
className,
|
className,
|
||||||
triggerContent = null,
|
triggerContent = null,
|
||||||
|
triggerClassName = 'quick-add__chip quick-add__trigger panel-floating-actions__trigger',
|
||||||
showStateIndicators = true,
|
showStateIndicators = true,
|
||||||
showCounts = true,
|
showCounts = true,
|
||||||
onOpenMenu = null,
|
onOpenMenu = null,
|
||||||
renderItemLabel = null,
|
renderItemLabel = null,
|
||||||
|
positionStrategy = 'absolute',
|
||||||
}) => {
|
}) => {
|
||||||
const anchorRef = useRef(null);
|
const anchorRef = useRef(null);
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
@@ -55,7 +53,7 @@ const SelectionAssignmentMenu = ({
|
|||||||
} = useFloatingMenu({
|
} = useFloatingMenu({
|
||||||
anchorRef,
|
anchorRef,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
positionStrategy: 'absolute',
|
positionStrategy,
|
||||||
minWidth: 220,
|
minWidth: 220,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,7 +115,8 @@ const SelectionAssignmentMenu = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleCreate = useCallback(
|
const handleCreate = useCallback(
|
||||||
async () => {
|
async (event) => {
|
||||||
|
event?.preventDefault?.();
|
||||||
if (typeof onCreate !== 'function') {
|
if (typeof onCreate !== 'function') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -144,9 +143,12 @@ const SelectionAssignmentMenu = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const canCreate = Boolean(onCreate);
|
const canCreate = Boolean(onCreate);
|
||||||
const showCreateOption = canCreate
|
const trimmedQuery = query.trim();
|
||||||
&& query.trim().length > 0
|
const queryKey = trimmedQuery.toLowerCase();
|
||||||
&& !existingLabels.has(query.trim().toLowerCase());
|
const canSubmitCreate = canCreate
|
||||||
|
&& trimmedQuery.length > 0
|
||||||
|
&& !existingLabels.has(queryKey)
|
||||||
|
&& !pending;
|
||||||
|
|
||||||
const handleTriggerClick = useCallback(() => {
|
const handleTriggerClick = useCallback(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
@@ -163,7 +165,7 @@ const SelectionAssignmentMenu = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
ref={anchorRef}
|
ref={anchorRef}
|
||||||
className="quick-add__chip quick-add__trigger panel-floating-actions__trigger"
|
className={triggerClassName}
|
||||||
onClick={handleTriggerClick}
|
onClick={handleTriggerClick}
|
||||||
aria-haspopup="menu"
|
aria-haspopup="menu"
|
||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
@@ -184,6 +186,7 @@ const SelectionAssignmentMenu = ({
|
|||||||
data-floating-position
|
data-floating-position
|
||||||
>
|
>
|
||||||
<div className="selection-assignment__header">
|
<div className="selection-assignment__header">
|
||||||
|
<form className="selection-assignment__form" onSubmit={handleCreate}>
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -193,6 +196,18 @@ const SelectionAssignmentMenu = ({
|
|||||||
aria-label={placeholder}
|
aria-label={placeholder}
|
||||||
disabled={pending}
|
disabled={pending}
|
||||||
/>
|
/>
|
||||||
|
{canCreate ? (
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="icon-button selection-assignment__add"
|
||||||
|
disabled={!canSubmitCreate}
|
||||||
|
aria-label={createLabel || 'Add'}
|
||||||
|
title={createLabel || 'Add'}
|
||||||
|
>
|
||||||
|
<PlusIcon aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div className="selection-assignment__list" role="presentation">
|
<div className="selection-assignment__list" role="presentation">
|
||||||
{filteredItems.length ? (
|
{filteredItems.length ? (
|
||||||
@@ -237,19 +252,6 @@ const SelectionAssignmentMenu = ({
|
|||||||
<div className="menu__empty selection-assignment__empty">{emptyMessage}</div>
|
<div className="menu__empty selection-assignment__empty">{emptyMessage}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{showCreateOption ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="menu__item selection-assignment__create"
|
|
||||||
onClick={handleCreate}
|
|
||||||
disabled={pending}
|
|
||||||
>
|
|
||||||
<PlusIcon className="selection-assignment__icon" aria-hidden="true" />
|
|
||||||
<span className="selection-assignment__label">
|
|
||||||
{createLabel ? `${createLabel} “${query.trim()}”` : `Create “${query.trim()}”`}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -93,12 +93,13 @@ const createDocumentsSurface = ({
|
|||||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||||
const detail = detailOpen && detailProps
|
const detail = detailOpen && detailProps
|
||||||
? (() => {
|
? (() => {
|
||||||
const { onClose, onOpenPreview, ...restDetailProps } = detailProps;
|
const { onClose, onOpenPreview, tags: tagOptions, ...restDetailProps } = detailProps;
|
||||||
return (
|
return (
|
||||||
<DocumentViewerPanel
|
<DocumentViewerPanel
|
||||||
variant="sidebar"
|
variant="sidebar"
|
||||||
onCollapsePanel={onClose}
|
onCollapsePanel={onClose}
|
||||||
onMaximizePanel={onOpenPreview}
|
onMaximizePanel={onOpenPreview}
|
||||||
|
tagOptions={tagOptions}
|
||||||
{...restDetailProps}
|
{...restDetailProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -74,10 +74,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-panel__content .document-viewer-panel__body {
|
|
||||||
padding: 0.5rem 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-section__header {
|
.detail-section__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -195,7 +191,14 @@
|
|||||||
border-bottom: 1px solid var(--border-subtle);
|
border-bottom: 1px solid var(--border-subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
.selection-assignment__header input {
|
.selection-assignment__form {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.4rem;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection-assignment__form input {
|
||||||
|
flex: 1 1 auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.35rem 0.6rem;
|
padding: 0.35rem 0.6rem;
|
||||||
border: 1px solid var(--border-subtle);
|
border: 1px solid var(--border-subtle);
|
||||||
@@ -205,12 +208,20 @@
|
|||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selection-assignment__header input:focus-visible {
|
.selection-assignment__form input:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: color-mix(in oklch, var(--accent) 60%, transparent);
|
border-color: color-mix(in oklch, var(--accent) 60%, transparent);
|
||||||
box-shadow: 0 0 0 1px color-mix(in oklch, var(--accent) 35%, transparent);
|
box-shadow: 0 0 0 1px color-mix(in oklch, var(--accent) 35%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selection-assignment__add {
|
||||||
|
align-self: stretch;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.selection-assignment__list {
|
.selection-assignment__list {
|
||||||
max-height: max(240px, 50vh);
|
max-height: max(240px, 50vh);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -236,7 +236,7 @@
|
|||||||
box-shadow: 0 12px 28px var(--shadow-strong);
|
box-shadow: 0 12px 28px var(--shadow-strong);
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
z-index: 2500000;
|
z-index: 2500000;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu[data-floating-position] {
|
.menu[data-floating-position] {
|
||||||
@@ -247,6 +247,7 @@
|
|||||||
|
|
||||||
.menu__list {
|
.menu__list {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
max-height: min(20rem, 60vh);
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user