@columenlabs/lumen-ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +12 -0
- package/README.md +4 -2
- package/dist/add-column.d.ts +23 -0
- package/dist/add-column.js +62 -0
- package/dist/api-fetch.d.ts +9 -0
- package/dist/api-fetch.js +60 -0
- package/dist/app-switcher.d.ts +21 -0
- package/dist/app-switcher.js +12 -0
- package/dist/app-views.d.ts +18 -0
- package/dist/app-views.js +41 -0
- package/dist/assistant-context.d.ts +72 -0
- package/dist/assistant-context.js +30 -0
- package/dist/assistant-panel.d.ts +58 -0
- package/dist/assistant-panel.js +244 -0
- package/dist/assistant-screen.d.ts +124 -0
- package/dist/assistant-screen.js +252 -0
- package/dist/card-switch.d.ts +16 -0
- package/dist/card-switch.js +16 -0
- package/dist/color-dot.d.ts +14 -0
- package/dist/color-dot.js +19 -0
- package/dist/confirm.d.ts +18 -0
- package/dist/confirm.js +5 -0
- package/dist/connections.d.ts +45 -0
- package/dist/connections.js +275 -0
- package/dist/coverage-calendar-map.d.ts +27 -0
- package/dist/coverage-calendar-map.js +84 -0
- package/dist/coverage-cells.d.ts +55 -0
- package/dist/coverage-cells.js +85 -0
- package/dist/coverage-map.d.ts +112 -0
- package/dist/coverage-map.js +434 -0
- package/dist/details-table.d.ts +20 -0
- package/dist/details-table.js +17 -0
- package/dist/drawer-section.d.ts +27 -0
- package/dist/drawer-section.js +23 -0
- package/dist/floating-head.d.ts +2 -0
- package/dist/floating-head.js +57 -0
- package/dist/fold.d.ts +16 -0
- package/dist/fold.js +70 -0
- package/dist/form-issues.d.ts +32 -0
- package/dist/form-issues.js +60 -0
- package/dist/formula-input.d.ts +17 -0
- package/dist/formula-input.js +104 -0
- package/dist/frame-script.d.ts +7 -0
- package/dist/frame-script.js +103 -0
- package/dist/freshness.d.ts +24 -0
- package/dist/freshness.js +99 -0
- package/dist/group-button.d.ts +33 -0
- package/dist/group-button.js +67 -0
- package/dist/growth-chart.d.ts +77 -0
- package/dist/growth-chart.js +195 -0
- package/dist/hooks/use-keyboard-fit.d.ts +15 -0
- package/dist/hooks/use-keyboard-fit.js +29 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/icon-button.d.ts +21 -0
- package/dist/icon-button.js +22 -0
- package/dist/icon-picker.d.ts +14 -0
- package/dist/icon-picker.js +36 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +90 -0
- package/dist/integrations.d.ts +57 -0
- package/dist/integrations.js +73 -0
- package/dist/joins.d.ts +127 -0
- package/dist/joins.js +767 -0
- package/dist/kit-config.d.ts +13 -0
- package/dist/kit-config.js +15 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/lumen-boundary.d.ts +7 -0
- package/dist/lumen-boundary.js +10 -0
- package/dist/lumen-code-editor-impl.d.ts +2 -0
- package/dist/lumen-code-editor-impl.js +16 -0
- package/dist/lumen-code-editor.d.ts +11 -0
- package/dist/lumen-code-editor.js +11 -0
- package/dist/lumen-code.d.ts +22 -0
- package/dist/lumen-code.js +79 -0
- package/dist/lumen-drawer.d.ts +30 -0
- package/dist/lumen-drawer.js +29 -0
- package/dist/lumen-echart.d.ts +58 -0
- package/dist/lumen-echart.js +129 -0
- package/dist/lumen-filter.d.ts +75 -0
- package/dist/lumen-filter.js +554 -0
- package/dist/lumen-finder.d.ts +62 -0
- package/dist/lumen-finder.js +275 -0
- package/dist/lumen-form.d.ts +34 -0
- package/dist/lumen-form.js +81 -0
- package/dist/lumen-geo-map.d.ts +9 -0
- package/dist/lumen-geo-map.js +121 -0
- package/dist/lumen-grid.d.ts +49 -0
- package/dist/lumen-grid.js +205 -0
- package/dist/lumen-layout.d.ts +150 -0
- package/dist/lumen-layout.js +658 -0
- package/dist/lumen-links.d.ts +96 -0
- package/dist/lumen-links.js +213 -0
- package/dist/lumen-page-state.d.ts +20 -0
- package/dist/lumen-page-state.js +15 -0
- package/dist/lumen-selector.d.ts +139 -0
- package/dist/lumen-selector.js +308 -0
- package/dist/lumen-source.d.ts +137 -0
- package/dist/lumen-source.js +329 -0
- package/dist/lumen-tab-drawer.d.ts +27 -0
- package/dist/lumen-tab-drawer.js +26 -0
- package/dist/lumen-tabs.d.ts +21 -0
- package/dist/lumen-tabs.js +6 -0
- package/dist/lumen-toast.d.ts +11 -0
- package/dist/lumen-toast.js +16 -0
- package/dist/lumen-trend.d.ts +18 -0
- package/dist/lumen-trend.js +157 -0
- package/dist/lumen-view-card.d.ts +35 -0
- package/dist/lumen-view-card.js +50 -0
- package/dist/lumen-view.d.ts +172 -0
- package/dist/lumen-view.js +647 -0
- package/dist/lumen-widget-charts.d.ts +57 -0
- package/dist/lumen-widget-charts.js +69 -0
- package/dist/lumen-widget.d.ts +614 -0
- package/dist/lumen-widget.js +598 -0
- package/dist/market/compare-chart.d.ts +34 -0
- package/dist/market/compare-chart.js +292 -0
- package/dist/market/indicator-picker.d.ts +29 -0
- package/dist/market/indicator-picker.js +125 -0
- package/dist/market/indicators.d.ts +63 -0
- package/dist/market/indicators.js +314 -0
- package/dist/market/live.d.ts +120 -0
- package/dist/market/live.js +444 -0
- package/dist/market/lumen-chart.d.ts +88 -0
- package/dist/market/lumen-chart.js +645 -0
- package/dist/market/market-widget.d.ts +45 -0
- package/dist/market/market-widget.js +346 -0
- package/dist/market/option-chain.d.ts +19 -0
- package/dist/market/option-chain.js +53 -0
- package/dist/market/price-chart.d.ts +128 -0
- package/dist/market/price-chart.js +619 -0
- package/dist/mcp-settings.d.ts +20 -0
- package/dist/mcp-settings.js +65 -0
- package/dist/nav.d.ts +77 -0
- package/dist/nav.js +73 -0
- package/dist/note-line.d.ts +13 -0
- package/dist/note-line.js +5 -0
- package/dist/notifications.d.ts +9 -0
- package/dist/notifications.js +168 -0
- package/dist/origin-legend.d.ts +14 -0
- package/dist/origin-legend.js +38 -0
- package/dist/overview.d.ts +84 -0
- package/dist/overview.js +105 -0
- package/dist/page-inputs.d.ts +14 -0
- package/dist/page-inputs.js +16 -0
- package/dist/page.d.ts +32 -0
- package/dist/page.js +45 -0
- package/dist/pager.d.ts +10 -0
- package/dist/pager.js +14 -0
- package/dist/prefs.d.ts +71 -0
- package/dist/prefs.js +126 -0
- package/dist/query-client.d.ts +7 -0
- package/dist/query-client.js +19 -0
- package/dist/refresh.d.ts +4 -0
- package/dist/refresh.js +19 -0
- package/dist/rename-field.d.ts +11 -0
- package/dist/rename-field.js +26 -0
- package/dist/reset-button.d.ts +9 -0
- package/dist/reset-button.js +10 -0
- package/dist/route-error.d.ts +42 -0
- package/dist/route-error.js +229 -0
- package/dist/schedules.d.ts +88 -0
- package/dist/schedules.js +221 -0
- package/dist/settings.d.ts +51 -0
- package/dist/settings.js +183 -0
- package/dist/shell.d.ts +99 -0
- package/dist/shell.js +137 -0
- package/dist/source-health.d.ts +12 -0
- package/dist/source-health.js +58 -0
- package/dist/spotlight.d.ts +23 -0
- package/dist/spotlight.js +138 -0
- package/dist/status-health.d.ts +16 -0
- package/dist/status-health.js +41 -0
- package/dist/status.d.ts +9 -0
- package/dist/status.js +12 -0
- package/dist/summary-cards.d.ts +56 -0
- package/dist/summary-cards.js +274 -0
- package/dist/symbol-sheet-context.d.ts +4 -0
- package/dist/symbol-sheet-context.js +5 -0
- package/dist/symbol-sheet.d.ts +9 -0
- package/dist/symbol-sheet.js +24 -0
- package/dist/tasks.d.ts +29 -0
- package/dist/tasks.js +278 -0
- package/dist/theme.css +606 -0
- package/dist/tile.d.ts +37 -0
- package/dist/tile.js +25 -0
- package/dist/ui/alert-dialog.d.ts +18 -0
- package/dist/ui/alert-dialog.js +41 -0
- package/dist/ui/alert.d.ts +10 -0
- package/dist/ui/alert.js +27 -0
- package/dist/ui/avatar.d.ts +11 -0
- package/dist/ui/avatar.js +22 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/badge.js +27 -0
- package/dist/ui/breadcrumb.d.ts +11 -0
- package/dist/ui/breadcrumb.js +27 -0
- package/dist/ui/button-group.d.ts +11 -0
- package/dist/ui/button-group.js +27 -0
- package/dist/ui/button.d.ts +10 -0
- package/dist/ui/button.js +38 -0
- package/dist/ui/card.d.ts +11 -0
- package/dist/ui/card.js +24 -0
- package/dist/ui/chart.d.ts +44 -0
- package/dist/ui/chart.js +120 -0
- package/dist/ui/checkbox.d.ts +4 -0
- package/dist/ui/checkbox.js +8 -0
- package/dist/ui/collapsible.d.ts +5 -0
- package/dist/ui/collapsible.js +12 -0
- package/dist/ui/combobox.d.ts +24 -0
- package/dist/ui/combobox.js +60 -0
- package/dist/ui/command.d.ts +18 -0
- package/dist/ui/command.js +34 -0
- package/dist/ui/dialog.d.ts +23 -0
- package/dist/ui/dialog.js +50 -0
- package/dist/ui/dropdown-menu.d.ts +29 -0
- package/dist/ui/dropdown-menu.js +50 -0
- package/dist/ui/emoji-picker.d.ts +6 -0
- package/dist/ui/emoji-picker.js +28 -0
- package/dist/ui/empty.d.ts +11 -0
- package/dist/ui/empty.js +33 -0
- package/dist/ui/field.d.ts +24 -0
- package/dist/ui/field.js +65 -0
- package/dist/ui/hover-card.d.ts +6 -0
- package/dist/ui/hover-card.js +13 -0
- package/dist/ui/input-group.d.ts +16 -0
- package/dist/ui/input-group.js +56 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +6 -0
- package/dist/ui/item.d.ts +23 -0
- package/dist/ui/item.js +67 -0
- package/dist/ui/kbd.d.ts +3 -0
- package/dist/ui/kbd.js +9 -0
- package/dist/ui/label.d.ts +4 -0
- package/dist/ui/label.js +7 -0
- package/dist/ui/popover.d.ts +10 -0
- package/dist/ui/popover.js +25 -0
- package/dist/ui/progress.d.ts +4 -0
- package/dist/ui/progress.js +9 -0
- package/dist/ui/resizable.d.ts +7 -0
- package/dist/ui/resizable.js +13 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/scroll-area.js +10 -0
- package/dist/ui/select.d.ts +15 -0
- package/dist/ui/select.js +36 -0
- package/dist/ui/separator.d.ts +4 -0
- package/dist/ui/separator.js +7 -0
- package/dist/ui/sheet.d.ts +14 -0
- package/dist/ui/sheet.js +54 -0
- package/dist/ui/sidebar.d.ts +69 -0
- package/dist/ui/sidebar.js +206 -0
- package/dist/ui/skeleton.d.ts +2 -0
- package/dist/ui/skeleton.js +6 -0
- package/dist/ui/slider.d.ts +4 -0
- package/dist/ui/slider.js +9 -0
- package/dist/ui/sonner.d.ts +3 -0
- package/dist/ui/sonner.js +24 -0
- package/dist/ui/spinner.d.ts +2 -0
- package/dist/ui/spinner.js +7 -0
- package/dist/ui/switch.d.ts +6 -0
- package/dist/ui/switch.js +7 -0
- package/dist/ui/table.d.ts +10 -0
- package/dist/ui/table.js +31 -0
- package/dist/ui/tabs.d.ts +7 -0
- package/dist/ui/tabs.js +22 -0
- package/dist/ui/textarea.d.ts +3 -0
- package/dist/ui/textarea.js +6 -0
- package/dist/ui/toggle-group.d.ts +10 -0
- package/dist/ui/toggle-group.js +22 -0
- package/dist/ui/toggle.d.ts +9 -0
- package/dist/ui/toggle.js +25 -0
- package/dist/ui/tooltip.d.ts +7 -0
- package/dist/ui/tooltip.js +16 -0
- package/dist/view-edit-cell.d.ts +49 -0
- package/dist/view-edit-cell.js +201 -0
- package/dist/view-editor.d.ts +52 -0
- package/dist/view-editor.js +940 -0
- package/dist/view-formulas.d.ts +61 -0
- package/dist/view-formulas.js +247 -0
- package/dist/view-icons.d.ts +20 -0
- package/dist/view-icons.js +70 -0
- package/dist/view-model.d.ts +390 -0
- package/dist/view-model.js +316 -0
- package/dist/whats-new.d.ts +3 -0
- package/dist/whats-new.js +53 -0
- package/dist/widget-controls.d.ts +9 -0
- package/dist/widget-controls.js +26 -0
- package/dist/widget-settings.d.ts +436 -0
- package/dist/widget-settings.js +290 -0
- package/dist/widget-thumbs.d.ts +3 -0
- package/dist/widget-thumbs.js +29 -0
- package/dist/workspace-keys.d.ts +12 -0
- package/dist/workspace-keys.js +13 -0
- package/dist/workspaces.d.ts +57 -0
- package/dist/workspaces.js +473 -0
- package/package.json +82 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface KitConfig {
|
|
2
|
+
/** The cookie that keeps each person's display preferences. */
|
|
3
|
+
prefsCookie: string;
|
|
4
|
+
/** The cookie's `domain`, to share it across an app's hosts; none: this host only. */
|
|
5
|
+
cookieDomain?: (host: string) => string | undefined;
|
|
6
|
+
/** What a market widget says where the app has no live feed. */
|
|
7
|
+
marketOff: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const KIT: KitConfig;
|
|
10
|
+
/** Runs `fn` after each `configureLumen` (preferences read again from the app's cookie). */
|
|
11
|
+
export declare function onConfigure(fn: () => void): void;
|
|
12
|
+
/** Sets what `c` names; the rest keep the kit's defaults. */
|
|
13
|
+
export declare function configureLumen(c: Partial<KitConfig>): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const KIT = {
|
|
2
|
+
prefsCookie: 'lumen_prefs',
|
|
3
|
+
marketOff: 'Live market data is not on this app.',
|
|
4
|
+
};
|
|
5
|
+
const changed = new Set();
|
|
6
|
+
/** Runs `fn` after each `configureLumen` (preferences read again from the app's cookie). */
|
|
7
|
+
export function onConfigure(fn) {
|
|
8
|
+
changed.add(fn);
|
|
9
|
+
}
|
|
10
|
+
/** Sets what `c` names; the rest keep the kit's defaults. */
|
|
11
|
+
export function configureLumen(c) {
|
|
12
|
+
Object.assign(KIT, c);
|
|
13
|
+
for (const fn of changed)
|
|
14
|
+
fn();
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare function LumenBoundary({ where, what, children, }: {
|
|
3
|
+
/** Logged with the error: the card's id, or the panel's name ("assistant"). */
|
|
4
|
+
where: string;
|
|
5
|
+
what?: 'card' | 'panel';
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
3
|
+
import { ErrorPage, isStaleBuildError, reloadForNewBuild, reportError } from './route-error.js';
|
|
4
|
+
export function LumenBoundary({ where, what = 'card', children, }) {
|
|
5
|
+
return (_jsx(ErrorBoundary, { onError: (error) => {
|
|
6
|
+
if (isStaleBuildError(error) && reloadForNewBuild())
|
|
7
|
+
return reportError(error, 'reload', where);
|
|
8
|
+
reportError(error, 'shown', where);
|
|
9
|
+
}, fallbackRender: ({ error, resetErrorBoundary }) => (_jsx(ErrorPage, { error: error, onRetry: resetErrorBoundary, what: what })), children: children }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// CodeMirror behind LumenCodeEditor, in its own chunk: loaded the first time an editor opens, so no
|
|
3
|
+
// page that only reads code (LumenCode, shiki) pays for it.
|
|
4
|
+
import { javascript } from '@codemirror/lang-javascript';
|
|
5
|
+
import { json } from '@codemirror/lang-json';
|
|
6
|
+
import { sql } from '@codemirror/lang-sql';
|
|
7
|
+
import { githubDark, githubLight } from '@uiw/codemirror-theme-github';
|
|
8
|
+
import CodeMirror, { EditorView } from '@uiw/react-codemirror';
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
import { resolvedTheme, usePrefs } from './prefs.js';
|
|
11
|
+
const LANGS = { js: () => javascript(), sql: () => sql(), json: () => json() };
|
|
12
|
+
export default function CodeEditor({ value, onChange, lang, wrap = false, readOnly = false, className, }) {
|
|
13
|
+
const prefs = usePrefs();
|
|
14
|
+
const extensions = useMemo(() => [...(lang ? [LANGS[lang]()] : []), ...(wrap ? [EditorView.lineWrapping] : [])], [lang, wrap]);
|
|
15
|
+
return (_jsx(CodeMirror, { value: value, onChange: onChange, readOnly: readOnly, theme: resolvedTheme(prefs) === 'dark' ? githubDark : githubLight, extensions: extensions, basicSetup: { foldGutter: false, highlightActiveLine: !readOnly }, height: "100%", className: className }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type LumenCodeLang = 'js' | 'sql' | 'json';
|
|
2
|
+
export interface LumenCodeEditorProps {
|
|
3
|
+
value: string;
|
|
4
|
+
onChange: (value: string) => void;
|
|
5
|
+
lang?: LumenCodeLang;
|
|
6
|
+
/** Wraps long lines instead of scrolling sideways (off by default). */
|
|
7
|
+
wrap?: boolean;
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function LumenCodeEditor({ className, ...props }: LumenCodeEditorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// The shell's one code editor: CodeMirror with syntax colour, line numbers
|
|
3
|
+
// and an optional wrap, in the GitHub light and dark colours LumenCode reads with. Where LumenCode
|
|
4
|
+
// shows code, this edits it; CodeMirror ships once suite-wide, in a chunk of its own.
|
|
5
|
+
import { Suspense, lazy } from 'react';
|
|
6
|
+
import { cn } from './lib/utils.js';
|
|
7
|
+
import { Skeleton } from './ui/skeleton.js';
|
|
8
|
+
const Impl = lazy(() => import('./lumen-code-editor-impl.js'));
|
|
9
|
+
export function LumenCodeEditor({ className, ...props }) {
|
|
10
|
+
return (_jsx("div", { "data-slot": "lumen-code-editor", className: cn('min-h-0 overflow-hidden rounded-lg border text-xs', className), children: _jsx(Suspense, { fallback: _jsx(Skeleton, { className: "h-full w-full rounded-none" }), children: _jsx(Impl, { ...props, className: "lumen-code-editor h-full" }) }) }));
|
|
11
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type Token = {
|
|
2
|
+
content: string;
|
|
3
|
+
htmlStyle?: Record<string, string>;
|
|
4
|
+
};
|
|
5
|
+
/** A file's language from its name (`playbook.py` → `py`). */
|
|
6
|
+
export declare const langOfPath: (path: string) => string;
|
|
7
|
+
/** Lines of shiki tokens for `code`, plain lines until they arrive or when the language is unknown. */
|
|
8
|
+
export declare function useCodeTokens(code: string, lang: string | undefined): Token[][] | null;
|
|
9
|
+
export type LumenCodeProps = {
|
|
10
|
+
code: string;
|
|
11
|
+
/** The fence tag or file extension; none draws plain text. */
|
|
12
|
+
lang?: string;
|
|
13
|
+
/** Wraps long lines instead of scrolling sideways. */
|
|
14
|
+
wrap?: boolean;
|
|
15
|
+
/** Numbers each line (files); off for chat snippets. */
|
|
16
|
+
lineNumbers?: boolean;
|
|
17
|
+
/** The label and copy icon over the code (chat); off where the page has its own (a file view). */
|
|
18
|
+
header?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function LumenCode({ code, lang, wrap, lineNumbers, header, className, }: LumenCodeProps): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The shell's one code block: shiki's light and dark tokens for the fence's
|
|
3
|
+
// language, scrolled sideways inside the block, a copy icon. The assistant's answers and scripts and
|
|
4
|
+
// An app's playbook files all draw through it, so shiki ships once suite-wide.
|
|
5
|
+
import { CheckIcon, CopyIcon } from 'lucide-react';
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import { toast } from 'sonner';
|
|
8
|
+
import { IconButton } from './icon-button.js';
|
|
9
|
+
import { cn } from './lib/utils.js';
|
|
10
|
+
/** shiki, created once on first use; each language is its own chunk, loaded the first time it shows. */
|
|
11
|
+
let highlighter = null;
|
|
12
|
+
function getHighlighter() {
|
|
13
|
+
highlighter ??= (async () => {
|
|
14
|
+
const [{ createHighlighterCore }, { createJavaScriptRegexEngine }] = await Promise.all([
|
|
15
|
+
import('shiki/core'),
|
|
16
|
+
import('shiki/engine/javascript'),
|
|
17
|
+
]);
|
|
18
|
+
return createHighlighterCore({
|
|
19
|
+
themes: [import('shiki/themes/github-light.mjs'), import('shiki/themes/github-dark.mjs')],
|
|
20
|
+
langs: [],
|
|
21
|
+
engine: createJavaScriptRegexEngine(),
|
|
22
|
+
});
|
|
23
|
+
})();
|
|
24
|
+
return highlighter;
|
|
25
|
+
}
|
|
26
|
+
/** The fence tag or file type shiki knows it by (`ts`, `py`, `sql`), or null for plain text. */
|
|
27
|
+
async function loadLang(h, lang) {
|
|
28
|
+
const id = lang.toLowerCase();
|
|
29
|
+
if (h.getLoadedLanguages().includes(id))
|
|
30
|
+
return id;
|
|
31
|
+
const { bundledLanguages } = await import('shiki/langs');
|
|
32
|
+
const load = bundledLanguages[id];
|
|
33
|
+
if (!load)
|
|
34
|
+
return null;
|
|
35
|
+
await h.loadLanguage(load);
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
38
|
+
/** A file's language from its name (`playbook.py` → `py`). */
|
|
39
|
+
export const langOfPath = (path) => path.split('.').pop() ?? '';
|
|
40
|
+
/** Lines of shiki tokens for `code`, plain lines until they arrive or when the language is unknown. */
|
|
41
|
+
export function useCodeTokens(code, lang) {
|
|
42
|
+
const [tokens, setTokens] = useState(null);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
let live = true;
|
|
45
|
+
setTokens(null);
|
|
46
|
+
if (!lang)
|
|
47
|
+
return;
|
|
48
|
+
getHighlighter().then(async (h) => {
|
|
49
|
+
const id = await loadLang(h, lang);
|
|
50
|
+
if (!live || !id)
|
|
51
|
+
return;
|
|
52
|
+
const out = h.codeToTokens(code, {
|
|
53
|
+
lang: id,
|
|
54
|
+
themes: { light: 'github-light', dark: 'github-dark' },
|
|
55
|
+
defaultColor: false,
|
|
56
|
+
});
|
|
57
|
+
setTokens(out.tokens);
|
|
58
|
+
});
|
|
59
|
+
return () => {
|
|
60
|
+
live = false;
|
|
61
|
+
};
|
|
62
|
+
}, [code, lang]);
|
|
63
|
+
return tokens;
|
|
64
|
+
}
|
|
65
|
+
export function LumenCode({ code, lang, wrap = false, lineNumbers = false, header = true, className, }) {
|
|
66
|
+
const text = code.replace(/\n$/, '');
|
|
67
|
+
const tokens = useCodeTokens(text, lang);
|
|
68
|
+
const [copied, setCopied] = useState(false);
|
|
69
|
+
const lines = tokens ?? text.split('\n').map((l) => [{ content: l }]);
|
|
70
|
+
const copy = () => navigator.clipboard.writeText(text).then(() => {
|
|
71
|
+
setCopied(true);
|
|
72
|
+
setTimeout(() => setCopied(false), 1500);
|
|
73
|
+
}, () => toast.error("Couldn't copy the code"));
|
|
74
|
+
return (_jsxs("div", { "data-slot": "lumen-code", "data-highlighted": tokens ? 'true' : 'false', className: cn('lumen-code min-w-0 text-xs leading-relaxed', wrap && 'lumen-code-wrap', lineNumbers && 'lumen-code-numbers', header && 'rounded-lg border bg-muted/40', className), children: [header && (_jsxs("div", { className: "flex h-7 items-center justify-between border-b pr-1 pl-3", children: [_jsx("span", { className: "font-mono text-xs text-muted-foreground", children: lang || 'text' }), _jsx(IconButton, { icon: copied ? CheckIcon : CopyIcon, label: copied ? 'Copied' : 'Copy code', size: "icon-xs", onClick: copy })] })), _jsx("pre", { className: "overflow-x-auto", children: _jsx("code", { children: lines.map((line, i) => (
|
|
75
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: lines have no other identity
|
|
76
|
+
_jsxs("span", { className: "line", children: [line.map((t, j) => (
|
|
77
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: tokens have no other identity
|
|
78
|
+
_jsx("span", { style: t.htmlStyle, children: t.content }, j))), '\n'] }, i))) }) })] }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** A drawer's width on desktop, as the resizable panel takes it ("32%", "320px"). */
|
|
3
|
+
type Size = `${number}%` | `${number}px`;
|
|
4
|
+
export interface LumenDrawerProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
/** A muted line under the title ("Active · invited Oct 16"); read aloud only when left out. */
|
|
9
|
+
description?: ReactNode;
|
|
10
|
+
/** Stacked DrawerSections; the drawer pads and scrolls them. */
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
/** The footer's actions, right-aligned (a destructive action, Cancel and Save); Close when left out. */
|
|
13
|
+
footer?: ReactNode;
|
|
14
|
+
/** Left side of the footer: a count or status line ("12 releases"). */
|
|
15
|
+
footerStart?: ReactNode;
|
|
16
|
+
/** Width on desktop: starts at `defaultSize`, drags between `minSize` and `maxSize`. */
|
|
17
|
+
defaultSize?: Size;
|
|
18
|
+
minSize?: Size;
|
|
19
|
+
maxSize?: Size;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The suite's one pullout drawer (named LumenDrawer), on every app.
|
|
23
|
+
* Phone: a bottom sheet. Desktop: a right-side panel over the page whose width drags at its left
|
|
24
|
+
* edge, 320px to 60% by default. The sheet spans the screen so the resizable group has room; only
|
|
25
|
+
* the handle and the drawer take the pointer, so a click beside it falls through to the overlay
|
|
26
|
+
* and closes it (`!` beats the inline pointer-events Radix sets on a modal's content). Its body
|
|
27
|
+
* holds DrawerSections; its footer is always there (actions on the right, Close by default).
|
|
28
|
+
*/
|
|
29
|
+
export declare function LumenDrawer({ open, onClose, title, description, children, footer, footerStart, defaultSize, minSize, maxSize, }: LumenDrawerProps): import("react").JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { XIcon } from 'lucide-react';
|
|
3
|
+
import { useIsMobile } from './hooks/use-mobile.js';
|
|
4
|
+
import { IconButton } from './icon-button.js';
|
|
5
|
+
import { Button } from './ui/button.js';
|
|
6
|
+
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './ui/resizable.js';
|
|
7
|
+
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from './ui/sheet.js';
|
|
8
|
+
/**
|
|
9
|
+
* The suite's one pullout drawer (named LumenDrawer), on every app.
|
|
10
|
+
* Phone: a bottom sheet. Desktop: a right-side panel over the page whose width drags at its left
|
|
11
|
+
* edge, 320px to 60% by default. The sheet spans the screen so the resizable group has room; only
|
|
12
|
+
* the handle and the drawer take the pointer, so a click beside it falls through to the overlay
|
|
13
|
+
* and closes it (`!` beats the inline pointer-events Radix sets on a modal's content). Its body
|
|
14
|
+
* holds DrawerSections; its footer is always there (actions on the right, Close by default).
|
|
15
|
+
*/
|
|
16
|
+
export function LumenDrawer({ open, onClose, title, description, children, footer, footerStart, defaultSize = '32%', minSize = '320px', maxSize = '60%', }) {
|
|
17
|
+
const isMobile = useIsMobile();
|
|
18
|
+
const head = (_jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [_jsx(SheetTitle, { className: "truncate", children: title }), _jsx(SheetDescription, { className: description ? 'truncate text-muted-foreground text-xs' : 'sr-only', children: description ?? 'Details' })] }));
|
|
19
|
+
const body = _jsx("div", { className: "flex flex-col px-4 pb-4", children: children });
|
|
20
|
+
// Every drawer has a footer, styled like a dialog's: the body scrolls above
|
|
21
|
+
// it and always ends on a clear edge. Without actions of its own it offers Close.
|
|
22
|
+
const foot = (_jsxs("footer", { "data-slot": "drawer-footer", className: "flex shrink-0 items-center gap-2 border-t bg-muted/50 px-4 py-2.5", children: [footerStart && (_jsx("div", { className: "min-w-0 flex-1 truncate text-muted-foreground text-xs", children: footerStart })), _jsx("div", { className: "ml-auto flex items-center gap-2", children: footer ?? (_jsx(SheetClose, { asChild: true, children: _jsx(Button, { type: "button", size: "sm", variant: "outline", children: "Close" }) })) })] }));
|
|
23
|
+
return (
|
|
24
|
+
// Not modal on desktop: the assistant, docked beside it, stays usable while the drawer is open.
|
|
25
|
+
_jsx(Sheet, { open: open, onOpenChange: (o) => !o && onClose(), modal: isMobile, children: isMobile ? (_jsxs(SheetContent, { side: "bottom", className: "max-h-[85svh] gap-0 overflow-hidden", children: [_jsx(SheetHeader, { className: "shrink-0 border-b", children: head }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pt-2", children: body }), foot] })) : (_jsx(SheetContent, { side: "right", showCloseButton: false,
|
|
26
|
+
// The resize handle's grab zone is wider than the handle, so a drag can start on the
|
|
27
|
+
// overlay; the panels library marks that pointerdown handled, and then it doesn't close.
|
|
28
|
+
onPointerDownOutside: (e) => e.detail.originalEvent.defaultPrevented && e.preventDefault(), className: "pointer-events-none! gap-0 border-0 bg-transparent shadow-none data-[side=right]:left-0 data-[side=right]:w-auto data-[side=right]:border-l-0 data-[side=right]:sm:max-w-none", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", children: [_jsx(ResizablePanel, { minSize: "40%" }), _jsx(ResizableHandle, { withHandle: true, className: "pointer-events-auto" }), _jsx(ResizablePanel, { defaultSize: defaultSize, minSize: minSize, maxSize: maxSize, "data-slot": "lumen-drawer", className: "pointer-events-auto bg-popover shadow-lg", children: _jsxs("section", { className: "flex h-full flex-col overflow-hidden", children: [_jsxs("header", { className: "flex shrink-0 items-center gap-2 border-b px-4 py-3", children: [head, _jsx(SheetClose, { asChild: true, children: _jsx(IconButton, { icon: XIcon, label: "Close", className: "ml-auto" }) })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pt-2", children: body }), foot] }) })] }) })) }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ECharts, EChartsCoreOption } from 'echarts/core';
|
|
2
|
+
export type EChartOption = EChartsCoreOption;
|
|
3
|
+
export type EChartHandlers = Record<string, (params: unknown, chart: ECharts) => void>;
|
|
4
|
+
/** The theme's colours as plain values, for chart options. */
|
|
5
|
+
export interface ChartTokens {
|
|
6
|
+
fg: string;
|
|
7
|
+
muted: string;
|
|
8
|
+
border: string;
|
|
9
|
+
card: string;
|
|
10
|
+
popover: string;
|
|
11
|
+
gain: string;
|
|
12
|
+
loss: string;
|
|
13
|
+
primary: string;
|
|
14
|
+
/** --chart-1 … --chart-10. */
|
|
15
|
+
series: string[];
|
|
16
|
+
font: string;
|
|
17
|
+
mono: string;
|
|
18
|
+
}
|
|
19
|
+
/** The theme's chart colours; new ones when light and dark flip. */
|
|
20
|
+
export declare function useChartTokens(): ChartTokens;
|
|
21
|
+
/** The look every chart shares: text, axes and tooltip in the theme's colours. */
|
|
22
|
+
export declare function baseOption(t: ChartTokens): EChartOption;
|
|
23
|
+
/** An axis in the theme's colours (merge into xAxis or yAxis). */
|
|
24
|
+
export declare function axisStyle(t: ChartTokens): {
|
|
25
|
+
axisLine: {
|
|
26
|
+
lineStyle: {
|
|
27
|
+
color: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
axisTick: {
|
|
31
|
+
lineStyle: {
|
|
32
|
+
color: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
axisLabel: {
|
|
36
|
+
color: string;
|
|
37
|
+
fontSize: number;
|
|
38
|
+
};
|
|
39
|
+
splitLine: {
|
|
40
|
+
lineStyle: {
|
|
41
|
+
color: string;
|
|
42
|
+
opacity: number;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
nameTextStyle: {
|
|
46
|
+
color: string;
|
|
47
|
+
fontSize: number;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export declare function LumenEChart({ option, height, on, className, label, }: {
|
|
51
|
+
option: EChartOption;
|
|
52
|
+
height?: number;
|
|
53
|
+
/** Event handlers by ECharts event name ('click', 'axisareaselected'). */
|
|
54
|
+
on?: EChartHandlers;
|
|
55
|
+
className?: string;
|
|
56
|
+
/** What the chart shows, for screen readers. */
|
|
57
|
+
label: string;
|
|
58
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { cn } from './lib/utils.js';
|
|
4
|
+
function readTokens() {
|
|
5
|
+
const css = getComputedStyle(document.documentElement);
|
|
6
|
+
const v = (name, fallback) => css.getPropertyValue(name).trim() || fallback;
|
|
7
|
+
return {
|
|
8
|
+
fg: v('--foreground', '#e6eaf2'),
|
|
9
|
+
muted: v('--muted-foreground', '#9aa4b8'),
|
|
10
|
+
border: v('--border', '#2a3242'),
|
|
11
|
+
card: v('--card', '#121826'),
|
|
12
|
+
popover: v('--popover', '#121826'),
|
|
13
|
+
gain: v('--gain', '#22c55e'),
|
|
14
|
+
loss: v('--loss', '#ef4444'),
|
|
15
|
+
primary: v('--primary', '#5b8cff'),
|
|
16
|
+
series: Array.from({ length: 10 }, (_, i) => v(`--chart-${i + 1}`, '#5b8cff')),
|
|
17
|
+
font: getComputedStyle(document.body).fontFamily || 'sans-serif',
|
|
18
|
+
mono: v('--font-mono', 'monospace'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** The theme's chart colours; new ones when light and dark flip. */
|
|
22
|
+
export function useChartTokens() {
|
|
23
|
+
const [t, setT] = useState(readTokens);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const o = new MutationObserver(() => setT(readTokens()));
|
|
26
|
+
o.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'style'] });
|
|
27
|
+
return () => o.disconnect();
|
|
28
|
+
}, []);
|
|
29
|
+
return t;
|
|
30
|
+
}
|
|
31
|
+
/** The parts of ECharts the shell draws with, registered once. */
|
|
32
|
+
let loading = null;
|
|
33
|
+
function loadECharts() {
|
|
34
|
+
loading ??= Promise.all([
|
|
35
|
+
import('echarts/core'),
|
|
36
|
+
import('echarts/charts'),
|
|
37
|
+
import('echarts/components'),
|
|
38
|
+
import('echarts/renderers'),
|
|
39
|
+
]).then(([core, charts, comps, renderers]) => {
|
|
40
|
+
core.use([
|
|
41
|
+
charts.HeatmapChart,
|
|
42
|
+
charts.ScatterChart,
|
|
43
|
+
charts.LineChart,
|
|
44
|
+
charts.BarChart,
|
|
45
|
+
charts.ParallelChart,
|
|
46
|
+
comps.GridComponent,
|
|
47
|
+
comps.TooltipComponent,
|
|
48
|
+
comps.VisualMapComponent,
|
|
49
|
+
comps.ParallelComponent,
|
|
50
|
+
comps.MarkLineComponent,
|
|
51
|
+
comps.TitleComponent,
|
|
52
|
+
comps.LegendComponent,
|
|
53
|
+
renderers.CanvasRenderer,
|
|
54
|
+
]);
|
|
55
|
+
return core;
|
|
56
|
+
});
|
|
57
|
+
return loading;
|
|
58
|
+
}
|
|
59
|
+
/** The look every chart shares: text, axes and tooltip in the theme's colours. */
|
|
60
|
+
export function baseOption(t) {
|
|
61
|
+
return {
|
|
62
|
+
backgroundColor: 'transparent',
|
|
63
|
+
textStyle: { color: t.muted, fontFamily: t.font, fontSize: 11 },
|
|
64
|
+
color: t.series,
|
|
65
|
+
animation: false,
|
|
66
|
+
tooltip: {
|
|
67
|
+
backgroundColor: t.popover,
|
|
68
|
+
borderColor: t.border,
|
|
69
|
+
textStyle: { color: t.fg, fontSize: 12 },
|
|
70
|
+
confine: true,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** An axis in the theme's colours (merge into xAxis or yAxis). */
|
|
75
|
+
export function axisStyle(t) {
|
|
76
|
+
return {
|
|
77
|
+
axisLine: { lineStyle: { color: t.border } },
|
|
78
|
+
axisTick: { lineStyle: { color: t.border } },
|
|
79
|
+
axisLabel: { color: t.muted, fontSize: 10 },
|
|
80
|
+
splitLine: { lineStyle: { color: t.border, opacity: 0.5 } },
|
|
81
|
+
nameTextStyle: { color: t.muted, fontSize: 11 },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function LumenEChart({ option, height = 260, on, className, label, }) {
|
|
85
|
+
const box = useRef(null);
|
|
86
|
+
const chart = useRef(null);
|
|
87
|
+
const [ready, setReady] = useState(false);
|
|
88
|
+
const handlers = useRef(on);
|
|
89
|
+
handlers.current = on;
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
let alive = true;
|
|
92
|
+
let ro = null;
|
|
93
|
+
loadECharts().then((core) => {
|
|
94
|
+
if (!alive || !box.current)
|
|
95
|
+
return;
|
|
96
|
+
const c = core.init(box.current, undefined, { renderer: 'canvas' });
|
|
97
|
+
chart.current = c;
|
|
98
|
+
ro = new ResizeObserver(() => c.resize());
|
|
99
|
+
ro.observe(box.current);
|
|
100
|
+
setReady(true);
|
|
101
|
+
});
|
|
102
|
+
return () => {
|
|
103
|
+
alive = false;
|
|
104
|
+
ro?.disconnect();
|
|
105
|
+
chart.current?.dispose();
|
|
106
|
+
chart.current = null;
|
|
107
|
+
};
|
|
108
|
+
}, []);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (ready)
|
|
111
|
+
chart.current?.setOption(option, { notMerge: true });
|
|
112
|
+
}, [ready, option]);
|
|
113
|
+
const names = Object.keys(on ?? {}).join();
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const c = chart.current;
|
|
116
|
+
if (!ready || !c || !names)
|
|
117
|
+
return;
|
|
118
|
+
const bound = names.split(',').map((name) => {
|
|
119
|
+
const f = (p) => handlers.current?.[name]?.(p, c);
|
|
120
|
+
c.on(name, f);
|
|
121
|
+
return [name, f];
|
|
122
|
+
});
|
|
123
|
+
return () => {
|
|
124
|
+
for (const [name, f] of bound)
|
|
125
|
+
c.off(name, f);
|
|
126
|
+
};
|
|
127
|
+
}, [ready, names]);
|
|
128
|
+
return (_jsx("div", { ref: box, role: "img", "aria-label": label, className: cn('w-full', !ready && 'animate-pulse rounded-md bg-muted/40', className), style: { height } }));
|
|
129
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { JoinKey } from '@columenlabs/lumen-ui-types/domains';
|
|
2
|
+
import { type ViewTokenOp } from '@columenlabs/lumen-ui-types/views';
|
|
3
|
+
import { type LucideIcon } from 'lucide-react';
|
|
4
|
+
import { type FilterLink, type LinkColor } from './lumen-links.js';
|
|
5
|
+
export interface FilterField<T> {
|
|
6
|
+
key: string;
|
|
7
|
+
label: string;
|
|
8
|
+
icon: LucideIcon;
|
|
9
|
+
/** The row's values for this field (a row can carry several, like symbols). */
|
|
10
|
+
values: (row: T) => string[];
|
|
11
|
+
/**
|
|
12
|
+
* A number field: filtered by one condition, `> 100`, `< 0`, `= 5` or
|
|
13
|
+
* between, instead of by values.
|
|
14
|
+
*/
|
|
15
|
+
number?: (row: T) => number | null;
|
|
16
|
+
}
|
|
17
|
+
export interface FilterToken {
|
|
18
|
+
key: string;
|
|
19
|
+
value: string;
|
|
20
|
+
/** Excluded: rows with this value are dropped ("not in"). */
|
|
21
|
+
not?: boolean;
|
|
22
|
+
/** A number condition; `value` is a number, or `a..b` for between. */
|
|
23
|
+
op?: ViewTokenOp;
|
|
24
|
+
/** Shared: its card's colour, set on the chips a coloured card publishes to
|
|
25
|
+
* its colour group. A filter box's own tokens no longer carry it. */
|
|
26
|
+
link?: LinkColor;
|
|
27
|
+
/** The key it stands for across domains (symbol = underlying = ticker; account), so a card on
|
|
28
|
+
* another domain follows it by that key. */
|
|
29
|
+
as?: JoinKey;
|
|
30
|
+
/** How it reads where its value is an id (a tapped account): shown in Following. */
|
|
31
|
+
text?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const tokenText: (t: FilterToken) => string;
|
|
34
|
+
/** The rows that pass `tokens` (a widget's own filter), by the same rules as the filter box. */
|
|
35
|
+
export declare function filterByTokens<T>(rows: T[], fields: FilterField<T>[], tokens: FilterToken[],
|
|
36
|
+
/** The row's text, for `contains` tokens. */
|
|
37
|
+
text?: (row: T) => string[]): T[];
|
|
38
|
+
/** Keeps the tokens and text, and filters `rows` by them. */
|
|
39
|
+
export declare function useLumenFilter<T>(rows: T[], fields: FilterField<T>[], { text: textOf, initial, }?: {
|
|
40
|
+
/** Free-text haystack per row (a name, an id), besides the field values. */
|
|
41
|
+
text?: (row: T) => string[];
|
|
42
|
+
/** Tokens applied when the view opens (a view's default filters). */
|
|
43
|
+
initial?: FilterToken[];
|
|
44
|
+
}): {
|
|
45
|
+
fields: FilterField<T>[];
|
|
46
|
+
rows: T[];
|
|
47
|
+
indexed: {
|
|
48
|
+
row: T;
|
|
49
|
+
values: Record<string, string[]>;
|
|
50
|
+
nums: Record<string, number | null>;
|
|
51
|
+
}[];
|
|
52
|
+
tokens: FilterToken[];
|
|
53
|
+
setTokens: (next: FilterToken[]) => void;
|
|
54
|
+
text: string;
|
|
55
|
+
setText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
56
|
+
results: T[];
|
|
57
|
+
hasText: boolean;
|
|
58
|
+
};
|
|
59
|
+
export type LumenFilterState<T> = ReturnType<typeof useLumenFilter<T>>;
|
|
60
|
+
export declare function LumenTokenizedFilter<T>({ filter, placeholder, label, className, saved, onSave, changed, link: given, }: {
|
|
61
|
+
filter: LumenFilterState<T>;
|
|
62
|
+
placeholder?: string;
|
|
63
|
+
/** The input's accessible name. */
|
|
64
|
+
label?: string;
|
|
65
|
+
className?: string;
|
|
66
|
+
/** The view's saved filters; the save button shows when the box differs from them. */
|
|
67
|
+
saved?: FilterToken[];
|
|
68
|
+
/** Saves the box's filters as the view's own. */
|
|
69
|
+
onSave?: (tokens: FilterToken[]) => void;
|
|
70
|
+
/** Other unsaved changes the save icon also saves (the page's link colours). */
|
|
71
|
+
changed?: boolean;
|
|
72
|
+
/** Its card's link colour; a coloured card shares every chip. `null`: it
|
|
73
|
+
* never shares (a widget's own fixed filter). */
|
|
74
|
+
link?: FilterLink | null;
|
|
75
|
+
}): import("react").JSX.Element;
|