@hachej/boring-data-explorer 0.1.40 → 0.1.41
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/dist/front/index.d.ts +10 -2
- package/dist/front/index.js +96 -43
- package/package.json +2 -2
package/dist/front/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ReactNode, ComponentType } from 'react';
|
|
3
3
|
import { ExplorerDataSource, FacetConfig, ExplorerItem, DragPayload, Facets } from '../shared/index.js';
|
|
4
4
|
export { Badge, FacetValue, FacetsArgs, SearchArgs, SearchResult } from '../shared/index.js';
|
|
5
5
|
|
|
@@ -16,6 +16,12 @@ type DataExplorerProps = {
|
|
|
16
16
|
/** Empty state shown when the top-level result has no rows and no query/filters. */
|
|
17
17
|
emptyState?: ReactNode;
|
|
18
18
|
searchPlaceholder?: string;
|
|
19
|
+
/** Optional title rendered inside the explorer toolbar (for chromeless left tabs). */
|
|
20
|
+
toolbarTitle?: ReactNode;
|
|
21
|
+
/** Optional icon rendered before toolbarTitle. */
|
|
22
|
+
toolbarIcon?: ComponentType<{
|
|
23
|
+
className?: string;
|
|
24
|
+
}>;
|
|
19
25
|
/** Hide the search input. Default true. */
|
|
20
26
|
searchable?: boolean;
|
|
21
27
|
/**
|
|
@@ -26,12 +32,14 @@ type DataExplorerProps = {
|
|
|
26
32
|
query?: string;
|
|
27
33
|
/** Called when the toolbar search changes. Use with `query` for controlled per-tab search. */
|
|
28
34
|
onQueryChange?: (query: string) => void;
|
|
35
|
+
/** Optional external chrome target for toolbar-only actions such as filters. */
|
|
36
|
+
toolbarPortalElement?: Element | null;
|
|
29
37
|
/** Page size and debounce — passed through to useExplorerState. */
|
|
30
38
|
pageSize?: number;
|
|
31
39
|
debounceMs?: number;
|
|
32
40
|
className?: string;
|
|
33
41
|
};
|
|
34
|
-
declare function DataExplorer({ adapter, facets: facetConfigs, groupBy, onActivate, getDragPayload, emptyState, searchPlaceholder, searchable, query, onQueryChange, pageSize, debounceMs, className, }: DataExplorerProps): react_jsx_runtime.JSX.Element;
|
|
42
|
+
declare function DataExplorer({ adapter, facets: facetConfigs, groupBy, onActivate, getDragPayload, emptyState, searchPlaceholder, toolbarTitle, toolbarIcon, searchable, query, onQueryChange, toolbarPortalElement, pageSize, debounceMs, className, }: DataExplorerProps): react_jsx_runtime.JSX.Element;
|
|
35
43
|
|
|
36
44
|
type UseExplorerStateOptions = {
|
|
37
45
|
adapter: ExplorerDataSource;
|
package/dist/front/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/front/DataExplorer.tsx
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
3
4
|
import { ChevronRightIcon, ChevronDownIcon, FilterIcon, SearchIcon, XIcon } from "lucide-react";
|
|
4
5
|
|
|
5
6
|
// src/front/utils.ts
|
|
@@ -353,9 +354,12 @@ function DataExplorer({
|
|
|
353
354
|
getDragPayload,
|
|
354
355
|
emptyState = "No results",
|
|
355
356
|
searchPlaceholder = "Search\u2026",
|
|
357
|
+
toolbarTitle,
|
|
358
|
+
toolbarIcon,
|
|
356
359
|
searchable = true,
|
|
357
360
|
query,
|
|
358
361
|
onQueryChange,
|
|
362
|
+
toolbarPortalElement,
|
|
359
363
|
pageSize,
|
|
360
364
|
debounceMs,
|
|
361
365
|
className
|
|
@@ -375,6 +379,9 @@ function DataExplorer({
|
|
|
375
379
|
const hasFilters = Object.values(state.filters).some((v) => v.length > 0);
|
|
376
380
|
const treeMode = !!groupBy && !hasQuery && !hasFilters;
|
|
377
381
|
const filterCount = Object.values(state.filters).reduce((n, v) => n + v.length, 0);
|
|
382
|
+
const useExternalToolbarActions = Boolean(
|
|
383
|
+
toolbarPortalElement && !showSearch && facetConfigs?.length && !toolbarTitle
|
|
384
|
+
);
|
|
378
385
|
const groupEntries = useMemo(() => {
|
|
379
386
|
if (!treeMode || !groupBy) return [];
|
|
380
387
|
const config = facetConfigs?.find((f) => f.key === groupBy);
|
|
@@ -395,11 +402,27 @@ function DataExplorer({
|
|
|
395
402
|
}, [treeMode, groupBy, facetConfigs, state.facets]);
|
|
396
403
|
const showEmpty = !state.loading && !treeMode && state.topItems.length === 0 && state.query.length === 0 && !hasFilters;
|
|
397
404
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full flex-col", className), "data-slot": "data-explorer", children: [
|
|
398
|
-
|
|
405
|
+
useExternalToolbarActions && toolbarPortalElement ? createPortal(
|
|
406
|
+
/* @__PURE__ */ jsx(
|
|
407
|
+
ExternalToolbarActions,
|
|
408
|
+
{
|
|
409
|
+
facetConfigs,
|
|
410
|
+
facets: state.facets,
|
|
411
|
+
filters: state.filters,
|
|
412
|
+
filterCount,
|
|
413
|
+
onToggleFilter: state.toggleFilter,
|
|
414
|
+
onClearFilters: state.clearFilters
|
|
415
|
+
}
|
|
416
|
+
),
|
|
417
|
+
toolbarPortalElement
|
|
418
|
+
) : null,
|
|
419
|
+
(showSearch || facetConfigs?.length) && !useExternalToolbarActions ? /* @__PURE__ */ jsx(
|
|
399
420
|
Toolbar,
|
|
400
421
|
{
|
|
401
422
|
searchable: showSearch,
|
|
402
423
|
searchPlaceholder,
|
|
424
|
+
title: toolbarTitle,
|
|
425
|
+
icon: toolbarIcon,
|
|
403
426
|
query: state.query,
|
|
404
427
|
onQueryChange: setToolbarQuery,
|
|
405
428
|
facetConfigs,
|
|
@@ -439,6 +462,8 @@ function DataExplorer({
|
|
|
439
462
|
function Toolbar({
|
|
440
463
|
searchable,
|
|
441
464
|
searchPlaceholder,
|
|
465
|
+
title,
|
|
466
|
+
icon: Icon,
|
|
442
467
|
query,
|
|
443
468
|
onQueryChange,
|
|
444
469
|
facetConfigs,
|
|
@@ -450,8 +475,12 @@ function Toolbar({
|
|
|
450
475
|
total
|
|
451
476
|
}) {
|
|
452
477
|
return /* @__PURE__ */ jsxs(UiToolbar, { className: "border-b border-border/60 px-2 py-1.5", children: [
|
|
478
|
+
title ? /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1.5 px-1", children: [
|
|
479
|
+
Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-foreground/80" }) : null,
|
|
480
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-[14px] font-medium tracking-tight text-foreground", children: title })
|
|
481
|
+
] }) : null,
|
|
453
482
|
total != null ? /* @__PURE__ */ jsx("span", { className: "px-1 font-mono text-[10.5px] uppercase tracking-[0.05em] text-muted-foreground/80", children: total.toLocaleString() }) : null,
|
|
454
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
483
|
+
/* @__PURE__ */ jsx("div", { className: title ? "w-1 shrink-0" : "flex-1" }),
|
|
455
484
|
searchable ? /* @__PURE__ */ jsxs(Popover, { children: [
|
|
456
485
|
/* @__PURE__ */ jsxs(
|
|
457
486
|
PopoverTrigger,
|
|
@@ -485,47 +514,71 @@ function Toolbar({
|
|
|
485
514
|
] }) : null
|
|
486
515
|
] })
|
|
487
516
|
] }) : null,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
517
|
+
/* @__PURE__ */ jsx(
|
|
518
|
+
FilterControl,
|
|
519
|
+
{
|
|
520
|
+
facetConfigs,
|
|
521
|
+
facets,
|
|
522
|
+
filters,
|
|
523
|
+
filterCount,
|
|
524
|
+
onToggleFilter,
|
|
525
|
+
onClearFilters
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
] });
|
|
529
|
+
}
|
|
530
|
+
function ExternalToolbarActions(props) {
|
|
531
|
+
return /* @__PURE__ */ jsx(FilterControl, { ...props });
|
|
532
|
+
}
|
|
533
|
+
function FilterControl({
|
|
534
|
+
facetConfigs,
|
|
535
|
+
facets,
|
|
536
|
+
filters,
|
|
537
|
+
filterCount,
|
|
538
|
+
onToggleFilter,
|
|
539
|
+
onClearFilters
|
|
540
|
+
}) {
|
|
541
|
+
if (!facetConfigs?.length) return null;
|
|
542
|
+
return /* @__PURE__ */ jsxs(Popover, { children: [
|
|
543
|
+
/* @__PURE__ */ jsxs(
|
|
544
|
+
PopoverTrigger,
|
|
545
|
+
{
|
|
546
|
+
"aria-label": "Filters",
|
|
547
|
+
className: cn(
|
|
548
|
+
"inline-flex h-7 items-center gap-1 rounded-sm px-1.5 text-[11px] text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground",
|
|
549
|
+
filterCount > 0 && "bg-muted text-foreground"
|
|
550
|
+
),
|
|
551
|
+
children: [
|
|
552
|
+
/* @__PURE__ */ jsx(FilterIcon, { size: 12 }),
|
|
553
|
+
filterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px]", children: filterCount }) : null
|
|
554
|
+
]
|
|
555
|
+
}
|
|
556
|
+
),
|
|
557
|
+
/* @__PURE__ */ jsxs(
|
|
558
|
+
PopoverContent,
|
|
559
|
+
{
|
|
560
|
+
side: "right",
|
|
561
|
+
align: "start",
|
|
562
|
+
sideOffset: 8,
|
|
563
|
+
className: "w-64 space-y-3 p-3 text-[12px]",
|
|
564
|
+
children: [
|
|
565
|
+
facetConfigs.map((config) => /* @__PURE__ */ jsx(
|
|
566
|
+
FacetSection,
|
|
567
|
+
{
|
|
568
|
+
config,
|
|
569
|
+
values: facets?.[config.key] ?? [],
|
|
570
|
+
selected: filters[config.key] ?? [],
|
|
571
|
+
onToggle: onToggleFilter
|
|
572
|
+
},
|
|
573
|
+
config.key
|
|
574
|
+
)),
|
|
575
|
+
filterCount > 0 ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "xs", onClick: onClearFilters, className: "gap-1 text-[11px] text-muted-foreground hover:text-foreground", children: [
|
|
576
|
+
/* @__PURE__ */ jsx(XIcon, { size: 11 }),
|
|
577
|
+
" Clear all"
|
|
578
|
+
] }) : null
|
|
579
|
+
]
|
|
580
|
+
}
|
|
581
|
+
)
|
|
529
582
|
] });
|
|
530
583
|
}
|
|
531
584
|
function FacetSection({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-data-explorer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"clsx": "^2.1.1",
|
|
42
42
|
"lucide-react": "^1.8.0",
|
|
43
43
|
"tailwind-merge": "^3.5.0",
|
|
44
|
-
"@hachej/boring-ui-kit": "0.1.
|
|
44
|
+
"@hachej/boring-ui-kit": "0.1.41"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@testing-library/jest-dom": "^6.9.1",
|