mirror of https://github.com/buster-so/buster.git
globall key press
This commit is contained in:
parent
fd2e61808c
commit
7787a72061
|
@ -33,7 +33,6 @@ export const MentionInputSuggestionsMentionsInput = forwardRef<
|
||||||
autoFocus={false}
|
autoFocus={false}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
className="sr-only hidden h-0 border-0 p-0 pointer-events-none w-full"
|
className="sr-only hidden h-0 border-0 p-0 pointer-events-none w-full"
|
||||||
// className="absolute -top-1 left-0 w-full h-full border border-red-500"
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command } from 'cmdk';
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { createContext, useContextSelector } from 'use-context-selector';
|
||||||
import { SearchEmptyState } from './SearchEmptyState';
|
import { SearchEmptyState } from './SearchEmptyState';
|
||||||
import { SearchFooter } from './SearchFooter';
|
import { SearchFooter } from './SearchFooter';
|
||||||
import { SearchInput } from './SearchInput';
|
import { SearchInput } from './SearchInput';
|
||||||
import { SearchModalContentItems } from './SearchModalContentItems';
|
import { SearchModalContentItems } from './SearchModalContentItems';
|
||||||
import type { SearchModalContentProps } from './search-modal.types';
|
import type { SearchItem, SearchModalContentProps } from './search-modal.types';
|
||||||
import { useViewSearchItem } from './useViewSearchItem';
|
import { useViewSearchItem } from './useViewSearchItem';
|
||||||
|
|
||||||
export const SearchModalContent = <M, T extends string>({
|
export const SearchModalContent = <M, T extends string>({
|
||||||
|
@ -26,18 +27,40 @@ export const SearchModalContent = <M, T extends string>({
|
||||||
onViewSearchItem,
|
onViewSearchItem,
|
||||||
});
|
});
|
||||||
const [searchValue, setSearchValue] = useState<string>(defaulSearchValue);
|
const [searchValue, setSearchValue] = useState<string>(defaulSearchValue);
|
||||||
|
const isCommandKeyPressedRef = useRef(false);
|
||||||
|
|
||||||
const onSearchChangePreflight = (searchValue: string) => {
|
const onSearchChangePreflight = (searchValue: string) => {
|
||||||
setSearchValue(searchValue);
|
setSearchValue(searchValue);
|
||||||
onSearchChange(searchValue);
|
onSearchChange(searchValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleKeyDownGlobal = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.metaKey || e.ctrlKey) {
|
||||||
|
isCommandKeyPressedRef.current = true;
|
||||||
|
}
|
||||||
|
handleKeyDown(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyUpGlobal = (e: React.KeyboardEvent) => {
|
||||||
|
if (!e.metaKey && !e.ctrlKey) {
|
||||||
|
isCommandKeyPressedRef.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSelectGlobal = (item: SearchItem<M, T>) => {
|
||||||
|
if (item?.onSelect) {
|
||||||
|
item.onSelect();
|
||||||
|
}
|
||||||
|
onSelect(item, isCommandKeyPressedRef.current ? 'navigate' : 'select');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Command
|
<Command
|
||||||
className="min-w-[650px] min-h-[450px] max-h-[75vh] bg-background flex flex-col"
|
className="min-w-[650px] min-h-[450px] max-h-[75vh] bg-background flex flex-col"
|
||||||
value={focusedValue}
|
value={focusedValue}
|
||||||
onValueChange={setFocusedValue}
|
onValueChange={setFocusedValue}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDownGlobal}
|
||||||
|
onKeyUp={handleKeyUpGlobal}
|
||||||
>
|
>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
|
@ -48,7 +71,7 @@ export const SearchModalContent = <M, T extends string>({
|
||||||
<div className="border-b" />
|
<div className="border-b" />
|
||||||
<SearchModalContentItems
|
<SearchModalContentItems
|
||||||
searchItems={searchItems}
|
searchItems={searchItems}
|
||||||
onSelect={onSelect}
|
onSelectGlobal={onSelectGlobal}
|
||||||
onViewSearchItem={onViewSearchItem}
|
onViewSearchItem={onViewSearchItem}
|
||||||
/>
|
/>
|
||||||
<SearchEmptyState emptyState={emptyState} />
|
<SearchEmptyState emptyState={emptyState} />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Command } from 'cmdk';
|
import { Command, useCommandState } from 'cmdk';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import type {
|
import type {
|
||||||
SearchItem,
|
SearchItem,
|
||||||
|
@ -8,15 +8,24 @@ import type {
|
||||||
SearchModalContentProps,
|
SearchModalContentProps,
|
||||||
} from './search-modal.types';
|
} from './search-modal.types';
|
||||||
|
|
||||||
|
type CommonProps<M, T extends string> = {
|
||||||
|
onSelectGlobal: (d: SearchItem<M, T>) => void;
|
||||||
|
};
|
||||||
|
|
||||||
export const SearchModalContentItems = <M, T extends string>({
|
export const SearchModalContentItems = <M, T extends string>({
|
||||||
searchItems,
|
searchItems,
|
||||||
onSelect,
|
onSelectGlobal,
|
||||||
onViewSearchItem,
|
}: Pick<SearchModalContentProps<M, T>, 'searchItems' | 'onViewSearchItem'> & CommonProps<M, T>) => {
|
||||||
}: Pick<SearchModalContentProps<M, T>, 'searchItems' | 'onSelect' | 'onViewSearchItem'>) => {
|
const hasResults = useCommandState((x) => x.filtered.count) > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Command.List className="flex flex-col overflow-y-auto flex-1">
|
<Command.List className={cn('flex flex-col overflow-y-auto flex-1', !hasResults && 'hidden')}>
|
||||||
{searchItems.map((item, index) => (
|
{searchItems.map((item, index) => (
|
||||||
<ItemsSelecter key={keyExtractor(item, index)} item={item} />
|
<ItemsSelecter
|
||||||
|
key={keyExtractor(item, index)}
|
||||||
|
item={item}
|
||||||
|
onSelectGlobal={onSelectGlobal}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Command.List>
|
</Command.List>
|
||||||
);
|
);
|
||||||
|
@ -29,14 +38,20 @@ const keyExtractor = <M, T extends string>(item: SearchItems<M, T>, index: numbe
|
||||||
return item.type + index;
|
return item.type + index;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ItemsSelecter = <M, T extends string>({ item }: { item: SearchItems<M, T> }) => {
|
const ItemsSelecter = <M, T extends string>({
|
||||||
|
item,
|
||||||
|
onSelectGlobal,
|
||||||
|
}: {
|
||||||
|
item: SearchItems<M, T>;
|
||||||
|
onSelectGlobal: (d: SearchItem<M, T>) => void;
|
||||||
|
}) => {
|
||||||
const type = item.type;
|
const type = item.type;
|
||||||
if (type === 'item') {
|
if (type === 'item') {
|
||||||
return <SearchItemComponent {...item} />;
|
return <SearchItemComponent {...item} onSelectGlobal={onSelectGlobal} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'group') {
|
if (type === 'group') {
|
||||||
return <SearchItemGroupComponent item={item} />;
|
return <SearchItemGroupComponent item={item} onSelectGlobal={onSelectGlobal} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'seperator') {
|
if (type === 'seperator') {
|
||||||
|
@ -48,16 +63,8 @@ const ItemsSelecter = <M, T extends string>({ item }: { item: SearchItems<M, T>
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SearchItemComponent = <M, T extends string>({
|
const SearchItemComponent = <M, T extends string>(item: SearchItem<M, T> & CommonProps<M, T>) => {
|
||||||
value,
|
const { value, label, secondaryLabel, tertiaryLabel, icon, disabled, onSelectGlobal } = item;
|
||||||
label,
|
|
||||||
secondaryLabel,
|
|
||||||
tertiaryLabel,
|
|
||||||
icon,
|
|
||||||
onSelect,
|
|
||||||
loading,
|
|
||||||
disabled,
|
|
||||||
}: SearchItem<M, T>) => {
|
|
||||||
return (
|
return (
|
||||||
<Command.Item
|
<Command.Item
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -68,10 +75,7 @@ const SearchItemComponent = <M, T extends string>({
|
||||||
)}
|
)}
|
||||||
value={value}
|
value={value}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onSelect={() => {
|
onSelect={() => onSelectGlobal(item)}
|
||||||
console.log('onSelect', value);
|
|
||||||
onSelect?.();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
|
@ -80,18 +84,24 @@ const SearchItemComponent = <M, T extends string>({
|
||||||
|
|
||||||
const SearchItemGroupComponent = <M, T extends string>({
|
const SearchItemGroupComponent = <M, T extends string>({
|
||||||
item,
|
item,
|
||||||
|
onSelectGlobal,
|
||||||
}: {
|
}: {
|
||||||
item: SearchItemGroup<M, T>;
|
item: SearchItemGroup<M, T>;
|
||||||
|
onSelectGlobal: (d: SearchItem<M, T>) => void;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Command.Group>
|
<Command.Group>
|
||||||
{item.items.map((item, index) => (
|
{item.items.map((item, index) => (
|
||||||
<ItemsSelecter key={keyExtractor(item, index)} item={item} />
|
<ItemsSelecter
|
||||||
|
key={keyExtractor(item, index)}
|
||||||
|
item={item}
|
||||||
|
onSelectGlobal={onSelectGlobal}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Command.Group>
|
</Command.Group>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SearchItemSeperatorComponent = ({ item }: { item: SearchItemSeperator }) => {
|
const SearchItemSeperatorComponent = ({ item: _item }: { item: SearchItemSeperator }) => {
|
||||||
return <Command.Separator className="border-t w-full" />;
|
return <Command.Separator className="border-t w-full" />;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue