pacocoursey / cmdk

Fast, unstyled command menu React component.
https://cmdk.paco.me
MIT License
9.42k stars 265 forks source link

Create New #75

Open emersonlaurentino opened 1 year ago

emersonlaurentino commented 1 year ago

It would be really cool if there were no result, just as it is possible to render Command.Empty there was also a Command.Create that could render a selected Item with the message Create new "${seach}".

I tried to do this, however, the Command.Item is rendered null when there are no filtered results.

https://github.com/pacocoursey/cmdk/blob/a7c974083d8b201f39dc5a340a65ae8472781574/cmdk/src/index.tsx#L603

Como seria legal que fosse

Proposal 1

<Command>
  <Command.Input />
  <Command.List>
    <Command.Item>Apple</Command.Item>
    <Command.Item create>Create New</Command.Item>
  </Command.List>
</Command>

Command.Item create would only be displayed when the filter count was 0 (like Command.Empty).

Proposal 2

<Command>
  <Command.Input />
  <Command.List>
    <Command.Item>Apple</Command.Item>
    <Command.Create>Create New</Command.Create>
  </Command.List>
</Command>

Command.Create would only be displayed when the filter count was 0 (like Command.Empty).

raunofreiberg commented 1 year ago

Hi.

Have you tried rendering a Command.Item where the value is the current input value?

<Command>
  <Command.Input value={inputValue} onChange={e => setInputValue(e.target.value)} />
  <Command.List>
    <Command.Item value={inputValue} onSelect={createNew}>
       Create new {inputValue}
    </Command.Item>
  </Command.List>
</Command>

This way it should always match the input query and even show up when no other results are matching.

pacocoursey commented 1 year ago

You may also wish to use the (advanced) useCommandState hook documented here:

const search = useCommandState((state) => state.search)
const isEmpty = useCommandState((state) => state.filtered.count === 0)
emersonlaurentino commented 1 year ago

You may also wish to use the (advanced) useCommandState hook documented here:

const search = useCommandState((state) => state.search)
const isEmpty = useCommandState((state) => state.filtered.count === 0)

I tried that way, but I couldn't render the Command.Item anyway.

emersonlaurentino commented 1 year ago

Have you tried rendering a Command.Item where the value is the current input value?

I'll test this approach.

emersonlaurentino commented 1 year ago

@raunofreiberg it worked, however when I search for something that ends with a space, the count goes to 0, thus removing the create new button.

So a strange behavior is when I search for a compound name it keeps blinking every space. Example:

"rauno" = true
"rauno " = false
"rauno f" = true
vainamov commented 1 year ago

I'm currently in a similar situation, where I have to implement several selectable items that should be displayed once there are no other matching items.

I have tried using the current search value from the state hook, managed to solve the problem mentioned here before but there was another flaw I couldn't figure out yet.

const search = useCommandState((state) => state.search);

return <Command.Item value={`create:${search}:`}>...</Command.Item>;

As you can see I added a character at the end of the current search value when using it as a value for the Item. This solves the issues described by @emersonlaurentino and makes the Item match even with spaces at the end.

With this solution (and any of the other I've tried so far too be honest) however, two problems remain:

gijsmin commented 1 year ago

Any updates on this? @vainamov even with your suggested solution, the empty screen keeps popping up with a space

TmLev commented 9 months ago

It's the third time this week I've encountered this problem and I still have no good solution in mind. Sometimes it just works, sometimes it doesn't.

cah4a commented 5 months ago

Got this working using:

<Command
   filter={(item, query) => {
      if (item === "+create+") {
         return 1;
      }
      if (item.toLowerCase().includes(query.trim().toLowerCase())) {
         return 1;
      }
      return 0;
   }}
>

and

const CommandCreateItem = ({ onSelect }: { onSelect: (value: string) => void }) => {
   const query = useCommandState((state) => state.search);
   if (!query || !onCreate) return null;
   return (
      <CommandItem
         forceMount
         value="+create+"
         onSelect={() => onSelect(query)}
      >
         <MdAdd className="mr-2" /> {query}
      </CommandItem>
   );
});

This definitely should be part of the lib.

andrioidApacta commented 4 months ago

I'm also having this issue. Passing search as the value causes React 18 to freak out with too many state changes. Ironically, that only happens inside of <Command.Empty> - the one inside List doesn't seem to mind.

If I create a new component without using Command.Item then keyboard navigation breaks.

Has anyone managed to get this working?

cah4a's resolution overrides the filtering - and I don't want that.