tab-search
v0.1.7
Published
<div align='center'><h1>Tab-search</h1><p>Adapter for frontend and backend to create database search filter</p>
Readme
Preview
Usage
Install and register the web component:
npm install tab-searchimport "tab-search/codemirror";No CodeMirror CSS import is required. The editor renders in shadow DOM, so it can run beside another CodeMirror editor without sharing .cm-* styles.
Use a schema endpoint:
<tab-search
src="/api/tab-search"
theme="light"
placeholder="Search users..."
></tab-search>
<script type="module">
const search = document.querySelector("tab-search");
search.addEventListener("change", ({ detail }) => {
console.log(detail.doc);
});
search.addEventListener("submit", ({ detail }) => {
console.log("Submit:", detail.doc);
});
search.addEventListener("error", ({ detail }) => {
console.error("Schema failed to load:", detail.error);
});
</script>Or set the schema directly:
import "tab-search/codemirror";
import type { TabSearchElement } from "tab-search/codemirror";
const search = document.querySelector("tab-search") as TabSearchElement;
search.schema = {
tables: {
user: {
id: { type: "number" },
email: { type: "string" },
},
},
};
search.value = "@user.id == 1";Supported properties and attributes:
| Name | Description |
| --- | --- |
| src | URL returning the autocomplete schema. |
| schema | Schema object property or JSON string attribute. Takes priority over src. |
| value | Current editor value. Updates are reactive. |
| placeholder | Empty editor text. |
| theme | light or dark. |
Events:
| Event | Detail |
| --- | --- |
| change | { doc } after a user edit. |
| submit | { doc } when Enter is pressed and autocomplete did not consume it. |
| ready | { schema, src } after a schema is installed. |
| error | { error, src } when schema parsing or loading fails. |
Entering plain text, for example สวัสดี, performs a broad LIKE search across the selected table's text columns.
Theming
The editor renders in shadow DOM, so external selectors like tab-search .cm-content { ... } will not reach inside. Theming is done via CSS custom properties on the host - custom properties inherit through the shadow boundary.
Override any subset of these on the tab-search element:
tab-search {
/* Editor chrome */
--ts-background: #fff;
--ts-foreground: #24292e;
--ts-caret: #24292e;
--ts-selection: #bbdfff;
--ts-selection-match: #bbdfff;
--ts-line-highlight: #f6f8fa;
--ts-gutter-background: #fff;
--ts-gutter-foreground: #6e7781;
/* Syntax */
--ts-keyword: #d73a49;
--ts-string: #22863a;
--ts-variable: #005cc5;
--ts-property: #6f42c1;
--ts-tag: #116329;
--ts-name: #22863a;
--ts-comment: #6a737d;
--ts-atom: #e36209;
--ts-heading: #24292e;
--ts-link: #22863a;
--ts-deleted: #b31d28;
--ts-deleted-bg: #ffeef0;
--ts-invalid: #cb2431;
/* Autocomplete tooltip */
--ts-tooltip-background: #fff;
--ts-tooltip-foreground: inherit;
--ts-tooltip-border: rgb(106, 106, 106);
--ts-tooltip-selected-background: rgb(59 130 246);
--ts-tooltip-selected-foreground: inherit;
}Unset variables fall back to the built-in light/dark defaults, so you only need to declare the ones you want to change. To wire it to shadcn/Tailwind tokens:
tab-search {
--ts-background: hsl(var(--background));
--ts-foreground: hsl(var(--foreground));
--ts-keyword: hsl(var(--primary));
--ts-comment: hsl(var(--muted-foreground));
/* ...etc */
}(Tailwind v4 with full color values: drop the hsl() wrapper.)
For changes that don't fit a variable - different syntax-tag mappings, fonts, etc. - build your own theme with LightInit / DarkInit from tab-search/codemirror and skip StarterKit's built-in switcher.
Svelte, Hono, Drizzle ORM
<!-- page.svelte -->
<script lang="ts">
import { mode } from "mode-watcher";
import { onMount } from "svelte";
onMount(async () => {
// Register only in the browser when using SSR.
await import("tab-search/codemirror");
});
</script>
<tab-search
src="/api/v3/user/tab"
theme={$mode} placeholder="Search something..."
onchange={console.log}
/>// main.ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import { Tab } from "tab-search/drizzle"
// drizzle
import * as schema from "$schema"
import db from '$database'
const app = new Hono()
const tab = Tab(schema)
// create user tab
const tab$user = tab.use("USER", schema.USER)
app.get('/tab', async (c) => {
return c.json(tab$user.codemirrorSchema())
})
app.post('/tab',async (c)=> {
const query = await c.req.text()
const [where, err] = await tab$user.prepare(query)
if (err) {
return c.json({ error: err.message }, 400)
}
const data = await db.query.USER.findMany({
where
})
return c.json(data)
})
serve({ fetch: app.fetch, port: 3000 }, (info) => {
console.log(`http://localhost:${info.port}`)
})Author
- boon4681
