timc1 / kbar Goto Github PK
View Code? Open in Web Editor NEWfast, portable, and extensible cmd+k interface for your site
Home Page: https://kbar.vercel.app
License: MIT License
fast, portable, and extensible cmd+k interface for your site
Home Page: https://kbar.vercel.app
License: MIT License
Similar to spotlight, it may be nice to be able to place our actions in different sections for more complex applications. For example lets say I wanted a "Navigation" section for all of my navigation items, then a "Contacts" section to search contacts, a "Posts" section to search posts, etc.
I am building an application that I'd like the user to be able to search the navigation, various commands, along with about 4 or 5 different entities at the same time in this universal search.
Cool idea, but the implementation seems pretty lacking at the moment. I installed it, added it to my app, and received these errors:
honeybadger.js?e9d7:1057 ./node_modules/kbar/lib/KBarContent.js:26:0
Module not found: Can't resolve '@reach/portal'
Import trace for requested module:
./node_modules/kbar/lib/index.js
./components/GlobalProviders/index.tsx
./pages/_app.tsx
https://nextjs.org/docs/messages/module-not-found
eval @ honeybadger.js?e9d7:1057
r @ fs.js:3
handleErrors @ hot-dev-client.js?5345:120
processMessage @ hot-dev-client.js?5345:170
eval @ hot-dev-client.js?5345:32
eval @ eventsource.js?a343:38
handleMessage @ eventsource.js?a343:36
honeybadger.js?e9d7:1057 ./node_modules/kbar/lib/KBarResults.js:25:0
Module not found: Can't resolve 'match-sorter'
Import trace for requested module:
./node_modules/kbar/lib/index.js
./components/GlobalProviders/index.tsx
./pages/_app.tsx
https://nextjs.org/docs/messages/module-not-found
eval @ honeybadger.js?e9d7:1057
r @ fs.js:3
handleErrors @ hot-dev-client.js?5345:120
processMessage @ hot-dev-client.js?5345:170
eval @ hot-dev-client.js?5345:32
eval @ eventsource.js?a343:38
handleMessage @ eventsource.js?a343:36
honeybadger.js?e9d7:1057 ./node_modules/kbar/lib/useStore.js:22:0
Module not found: Can't resolve 'fast-equals'
Import trace for requested module:
./node_modules/kbar/lib/KBarContextProvider.js
./node_modules/kbar/lib/index.js
./components/GlobalProviders/index.tsx
./pages/_app.tsx
https://nextjs.org/docs/messages/module-not-found
We already have a portal, so I'm not keen to install reach portal, or any of the other reach components. But also, shouldn't this thing just handle its own dependencies?
Also, seems not to be TypeScript ready. I get this error from TS:
Property 'options' is missing in type '{ children: ReactNode; actions: { id: string; name: string; shortcut: string[]; keywords: string; perform: () => Promise<boolean>; }[]; }' but required in type 'KBarProviderProps'.ts(2741)
... though I've seen no indication that "options" should be a required property.
I hope this might be worth a second look later on, when it's more fully baked.
It may be nice to allow developers to pass in their own custom keyboard shortcut to instantiate kbar if they didn't want to use the preconfigured cmd+k. Some apps for example use cmd+/. Others use cmd+shift+P.
We should probably bind the Ctrl key for non Mac users. Temporary solution is to use Window + ctrl + k
When using useRegisterActions
to dynamically add actions while components are mounted it's difficult to predict which order items will appear in, adding an optional priority
attribute to actions would put control of this in the developers hands while handling the boilerplate of sorting internally.
Just a little heads-up: The landing page at https://kbar.vercel.app/ doesn't actually contain the word "React" anywhere, this confused me a little when I saw the sample code with JSX syntax.
KBar currently takes a static data structure and handles all of the parsing internally. The current component structure is as follows:
KBar
KeyboardShortcuts
KBarAnimator
KBarSearch
KBar
handles the primary cmd+k/esc listeners, and coordinates when to show, animate, and hide the contentKeyboardShortcuts
attaches keydown listeners and matches the keystroke patterns with our actions objectKBarAnimator
leverages ResizeObserver
and the Web Animations API to coordinate the smooth transitions when the content updatesKBarSearch
handles the search and rendering of resultsSince all state management and rendering logic is within KBar
itself, it is currently impossible for users to customize their command menu to fit their brand.
Although we can theoretically expose props which enable users to pass certain configurations, this would lead us to quite a restrictive API.
Let's take a look at an approach:
Provide a way to hook into the internal state; e.g. visualState
, currentActionId
, actions
, and
a method to trigger internal state updates.
The component heirarchy would look something like this:
// app.tsx
<KBarProvider actions={actions}>
<Breadcrumbs /> // custom user component
<KBarAnimator>
<KBarSearch />
<KBarResults
//
onRender={(result) => (
<div>
// ...
</div>
)}
/>
</KBarAnimator>
</KBarProvider>
// <MyApp />
User defined components within the KBarProvider
can hook into the internal state through a useKBar
hook.
// breadcrumbs.tsx
function Breadcrumbs() {
const { actions, breadcrumbs } = useKBar((state) => ({
breadcrumbs: getBreadcrumbs(state)
}));
return (
<ul>
{breadcrumbs.map(breadcrumb => (
<li key={breadcrumb.id}>
<Button onClick={() => actions.setCurrentRootActionId(breadcrumb.id)}>{breadcrumb.name}</Button>
</li>
))}
</ul>
)
}
Stub for now, but I'd imagine users needing to temporarily disable kbar; e.g. when editing a rich text field.
We could have some actions immediately available and additional actions would be appended after a promise is resolved (or several promises for that matter). A dev defined loading indicator could optionally be displayed in the interim.
Most likely caused by scrollIntoView
:
Hi 👋🏻
I discovered the project today and I am a big fan! The problem is that it uses React, and it's not a framework I use :/
So I was wondering if it would be better to make the project monorepo in order to add a lot of integrations, like @kbar/react
, @kbar/vue
.... and @kbar/core
which contains the vanilla part.
What do you think about it?
As discussed, currently you have to pass an options object in order to get animations but it would be nice to enable these by default given they are a library selling point.
hey tim! Awsome work with the Kbar, i've been using it in my preact app - in dev mode it works fine but after production build it doesn't work. consider me a noob trying to solve things.
it shows something like this in console
vendor.822cbe4a.js:29 Uncaught TypeError: (0 , Zt.default) is not a function
at Gf (vendor.822cbe4a.js:29)
at Y.qf [as constructor] (vendor.822cbe4a.js:29)
at Y.Ho [as render] (vendor.822cbe4a.js:1)
at dr (vendor.822cbe4a.js:1)
at ti (vendor.822cbe4a.js:1)
at dr (vendor.822cbe4a.js:1)
at ti (vendor.822cbe4a.js:1)
at dr (vendor.822cbe4a.js:1)
at ti (vendor.822cbe4a.js:1)
at dr (vendor.822cbe4a.js:1)
Gf @ vendor.822cbe4a.js:29
qf @ vendor.822cbe4a.js:29
Ho @ vendor.822cbe4a.js:1
dr @ vendor.822cbe4a.js:1
ti @ vendor.822cbe4a.js:1
dr @ vendor.822cbe4a.js:1
ti @ vendor.822cbe4a.js:1
dr @ vendor.822cbe4a.js:1
ti @ vendor.822cbe4a.js:1
dr @ vendor.822cbe4a.js:1
Ie @ vendor.822cbe4a.js:1
(anonymous) @ index.dc5496f6.js:formatted:113
in index.js (pretty-printed) it highlights this portion
y(i(r.KBarProvider, {
actions: S,
children: [o(r.KBarPortal, {
children: o(r.KBarPositioner, {
children: i(r.KBarAnimator, {
style: B,
children: [o(r.KBarSearch, {
style: k,
placeholder: "Type a command or search\u2026"
}), o(r.KBarResults, {})]
})
})
}), o(g, {
children: o(v, {})
})]
}), document.getElementById("app"));
it'd be really great if you can help me with this. thanks in advance
We can probably remove the requirement to explicitly define parent
for an action and infer the the value based on the defined children
.
I love this concept, and I actually use a custom cmd+k
implementation for a project of mine. I'd love to swap that out with kbar, but my app does not use React. Do you have any plans to make a framework-agnostic (only typescript) version of kbar?
Currently state is managed directly in KBarContextProvider
. This breaks our usage of the publisher/subscriber as changes directly within the provider re render children.
Instead, we can move the state management to a separate hook, e.g. useStore
, which would return the memoized state.
Currently, styles can be applied via props; e.g. contentStyle
, backgroundStyle
for KBarContent
, and directly as style
for KBarSearch
. There should be a simpler way to customize styles which enable full flexibility for:
Currently, searching "dark" will only display the "Theme…" action. Clicking the "Theme…" action will then expose the "Light" and "Dark" actions.
It would be neat to displaying search results for nested actions by displaying a breadcrumb-like UI. Searching "dark" would then display a result like:
Theme… > Dark
Now that we have the new Results
API, it's probably good to get rid of the deprecated KBarResults
component completely.
Hi Tim! Nice to contribute with you again.
I've been exploring your solution with a Next.js with Tailwind + TypeScript and I see some improvements.
<KBarContent
accepts contentStyle
, but not contentClassname
, using Tailwind classes with style is not possible (at least as far as I know)KBarResults
component onRender
function uses three types action
, handlers
, state
, could you export them for creating custom components with this fully typed?KBarProvider
context provider .. options
prop is required, why not auto-configure some default animations? Also actions
prop is required, when they could be loaded dynamically.Tell me what do you think :)
I have a field on a form ( @mui Input, not that it matters, I think ) and when click on the empty field, Chrome helpfully gives me a list of values which have been entered previously. Clicking on one of them populates the field and raises an error with kbar:
TypeError
Cannot read properties of undefined (reading 'toLowerCase')
Call Stack
handleKeyDown
@openmsupply-client/host/../../node_modules/kbar/lib/InternalEvents.js:132:33
checking for null on the event.key
property works around it for me:
internalEvents.tsx:124
const key = event.key?.toLowerCase();
Shouldn't cause any issues setting key to null like this afaik - it just helps the early return a few lines later 🤷♂️
Currently actions must be registered up front – though this works well for static actions; e.g. navigating pages, triggering DOM events, it falls short of easily enabling users to generate actions on the fly.
Perhaps an API like so:
const { registerActions } = useKBar(() => {...});
React.useEffect(() => {
registerActions([
// ...
])
}, [])
Check for role=textbox
I have an application (dashboard.plaid.com), where we would like to display some search results if the query matches a certain regex. From what I can tell, this isn't currently supported but could be a useful feature!
@timc1 little hiccup on the ctrl+k
implementation. I think the command bar closes if k
is pressed? ctrl+j
works fine
Ideally if you have a shortcut on an action with no perform
attribute, but a children
attribute it should open the kbar with the correct active root action. eg,
When using the useRegisterActions
hook only the initial value is considered – PR incoming with fix.
Probably easiest to reproduce by temporarily increasing the enter animation, but I have repeatedly done it on my installation.
cmd+k
When the cursor stays hovered on top of, say the third result, keyboard navigating will jump between the first result and the third.
In the video below, we expect that each time the search query changes, the active result should be the first:
It would be great if I could select an icons that would display to the right of the action option like the picture above.
A simple solution would be to allow for an icon
key in the actions array that will take an icon component
comet BlogIcon = () => <AiNewspaperOutline />;
const actions = [
{
id: "blog",
name: "Blog",
shortcut: ["b"],
keywords: "writing words",
perform: () => (window.location.pathname = "blog"),
icon: BlogIcon
}
];
For mobile devices the buttons can help toggle but going back the last step is not there.
eg. I clicked on change theme, but want to go back to main menu instead of changing it.
It's possible (in the case of search for example) to have hundreds of results, currently all matching results are displayed even those outside of the scrollable area which slows down on large result sets.
Kbar should allow developers the option to provide more context to users by displaying a subtitle along with the name. In my specific use-case I'd like to expose my complex navigation to kbar. Because things are nested, it may be helpful to users to see a navigation path under the name.
This would look something like this.
Gizmo
Products▶
Electronics
To display the subtitle as shown above, we may do something like this in our actions array.
const actions = [
...
{
name: "Gizmo",
subtitle: "Products ▶ Electronics",
perform: () => window.location.pathname = "/products/electronics/gizmo"
},
...
];
If the search string contained words in subtitle
, kbar would return that given item.
Hello!
My config
https://monosnap.com/file/z1jWbzjMxXpYXwp0CSOrk3dLMHUFEn
On website, the only changes which happens after press cmd + k is overflow hidden added to html tag but not any dropdown is appearing
Hi, I'm trying kbar
in my app (created with create-react-app
where I use React 18 (18.0.0-alpha-cb8a50619-20210909
) and I get this error when starting the app:
Failed to compile.
./node_modules/kbar/lib/useStore.js 120:10
Module parse failed: Unexpected token (120:10)
File was processed with these loaders:
* ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
| class Publisher {
> getState;
| subscribers = [];
|
In my App.js I have:
const actions = [
{
id: "blog",
name: "Blog",
shortcut: ["b"],
keywords: "writing words",
perform: () => (window.location.pathname = "blog"),
},
{
id: "contact",
name: "Contact",
shortcut: ["c"],
keywords: "email",
perform: () => (window.location.pathname = "contact"),
},
];
export default function App() {
return (
<KBarProvider actions={actions}>
<App />
</KBarProvider>
);
}
EDIT: Seem like the importing of anything from import { ... } from "kbar";
is crashing the app.
Getting multiple can't resolves like this
ERROR in ./example/src/index.tsx 2:0-35 Module not found: Error: Can't resolve 'react-dom' in '/.../kbar-main/example/src'
ERROR in ./example/src/index.tsx 4:0-59 Module not found: Error: Can't resolve 'react-router-dom' in '/.../kbar- main/example/src'
ERROR in ./src/InternalKeyboardEvents.tsx 1:0-31 Module not found: Error: Can't resolve 'react' in '/.../kbar-main/src'
@ ./src/KBarContextProvider.tsx 3:0-62 9:41-63
@ ./example/src/App.tsx 23:0-61 42:45-57
@ ./example/src/index.tsx 3:0-24 5:153-156
Do you know what might be happening?
Hey,
I really like this component, but macOS have less than 10% of market share.
It would be nice to add alternative shortcuts for Windows (and probably Linux).
CTRL + K works well, menu could be opened and closed, but the shortcuts like "h for home" are not working, just nothing happens.
Hi there! First of all, thanks for this :)
I it really necessary to wrap our app with your context provider?
From what I can tell, only KBar
components actually need to access that context. There are no other exports (like custom hooks) that we can use anywhere else in our app (that would require the provider) – and, honestly, I don't see a use-case where that would be necessary.
If I'm not completely mistaken, this would just require an update to the docs.
Nice project! I recommend adding the keywords "command palette" in package.json
, README.md
and so on, because that's how most people refer to this kind of functionality.
When adding children actions dynamically to existing parent actions, we need to update the parent action.children
list.
https://github.com/timc1/kbar/blob/main/src/useStore.tsx#L46-L58
Hi @timc1 !
Really love this project, it's great.
I have been checking out the component in a pretty barebones project and noticed that storybook stops working with a pretty plain build config when I added this package.
Specifically I'm getting a bunch of loader issues like:
ERROR in ./node_modules/kbar/lib/useStore.js 104:12
Module parse failed: Unexpected token (104:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| exports.default = useStore;
| class Publisher {
> getState;
| subscribers = [];
| constructor(getState) {
@ ./node_modules/kbar/lib/KBarContextProvider.js 26:35-56
@ ./node_modules/kbar/lib/index.js
@ ./packages/common/src/ui/layout/tables/columns/CheckboxSelectionColumn.tsx
@ ./packages/common/src/ui/layout/tables/columns/index.ts
@ ./packages/common/src/ui/layout/tables/index.ts
@ ./packages/common/src/utils/testing.tsx
@ ./.storybook/preview.js
@ ./.storybook/preview.js-generated-config-entry.js
@ multi ./node_modules/@storybook/react/node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/esm/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/esm/frameworks/react/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/esm/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/esm/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/esm/preset/addParameter.js-generated-other-entry.js ./node_modules/@storybook/addon-measure/dist/esm/preset/preview.js-generated-other-entry.js ./node_modules/storybook-addon-outline/dist/esm/preset/addDecorator.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./node_modules/@storybook/react/node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry.js
Everything works fine if I alter the tsconfig.json
in this project to be es5
rather than ESNext
and rebuild - was curious if making this change would be something you'd think about doing (Or, if you can recommend a different change I can make that is easier?)
on "0.1.0-beta.1", I was using this to blur my background when Kbar is visible.
<KBarContent
contentStyle={{
...
}}
backgroundStyle={{
backdropFilter: 'blur(16px)'
}}
>
How can i use this in "0.1.0-beta.4"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.