tag picker
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,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,
|
||||||
@@ -117,7 +113,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 +141,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) {
|
||||||
@@ -184,6 +184,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 +194,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 +250,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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -191,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);
|
||||||
@@ -201,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;
|
||||||
|
|||||||
@@ -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