@gntik-ai/blocks 0.8.0 → 0.9.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/dist/index.d.ts +9 -2
- package/dist/index.js +55 -26
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/builders/LogViewer/LogViewer.test.tsx +11 -0
- package/src/builders/LogViewer/LogViewer.tsx +28 -22
- package/src/page-chrome/PageHeader/PageHeader.test.tsx +18 -0
- package/src/page-chrome/PageHeader/PageHeader.tsx +3 -1
- package/src/page-chrome/PageHeader/block.meta.ts +1 -1
- package/src/page-chrome/PageHeader/examples/Spanish.tsx +11 -0
- package/src/tables/DataTable/DataTable.labels.test.tsx +2 -0
- package/src/tables/DataTable/DataTable.locale.test.tsx +153 -0
- package/src/tables/DataTable/DataTable.server-pagination.test.tsx +1 -1
- package/src/tables/DataTable/DataTable.test.tsx +16 -0
- package/src/tables/DataTable/block.meta.ts +2 -0
- package/src/tables/DataTable/data-table-row.tsx +18 -2
- package/src/tables/DataTable/data-table-utils.ts +18 -4
- package/src/tables/DataTable/labels.ts +2 -0
package/dist/index.d.ts
CHANGED
|
@@ -2924,8 +2924,13 @@ export declare function selectionState(visibleIds: readonly string[], selected:
|
|
|
2924
2924
|
/** Selects all of `ids` when not all are selected; otherwise clears them. Other selections are kept. */
|
|
2925
2925
|
export declare function toggleAll(ids: readonly string[], selected: ReadonlySet<string>): Set<string>;
|
|
2926
2926
|
export declare function toggleOne(id: string, selected: ReadonlySet<string>): Set<string>;
|
|
2927
|
-
/**
|
|
2928
|
-
export
|
|
2927
|
+
/** Optional locale and boolean text for default cells. */
|
|
2928
|
+
export interface DataTableCellFormatOptions {
|
|
2929
|
+
locale?: string;
|
|
2930
|
+
booleanLabels?: [trueLabel: string, falseLabel: string];
|
|
2931
|
+
}
|
|
2932
|
+
/** Default cell text for a raw value. Omitting options preserves the legacy output. */
|
|
2933
|
+
export declare function formatCell(value: CellValue, options?: DataTableCellFormatOptions): ReactNode;
|
|
2929
2934
|
/** Groups rows by a field key or by a function returning the group key. */
|
|
2930
2935
|
export type DataTableGroupBy<T> = Extract<keyof T, string> | ((row: T) => string | number | null | undefined);
|
|
2931
2936
|
/** One group of rows, in display order. */
|
|
@@ -2998,6 +3003,8 @@ export declare function PaginationFooter({ total, page: pageProp, defaultPage, o
|
|
|
2998
3003
|
//#region src/tables/DataTable/labels.d.ts
|
|
2999
3004
|
/** Per-instance table chrome, including the composed PaginationFooter. Caller data stays caller-owned. */
|
|
3000
3005
|
interface DataTableLabels extends PaginationFooterLabels {
|
|
3006
|
+
booleanTrue: string;
|
|
3007
|
+
booleanFalse: string;
|
|
3001
3008
|
/** Non-virtual table overflow region; virtualized regions keep the caller caption. */
|
|
3002
3009
|
scrollRegion: string;
|
|
3003
3010
|
selectionCount: (count: number) => string;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment, createElement, useCallback, useEffect, useEffectEvent, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { Activity, Archive, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, BarChart3, Bookmark, Bot, Boxes, Braces, Building2, CalendarCheck, CalendarDays, Camera, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, CircleAlert, CircleCheck, CircleHelp, CircleX, Clock, Cog, Columns3, Copy, CreditCard, Database, Download, ExternalLink, Eye, FileCode, FileText, FolderKanban, FolderPlus, Gauge, GitBranch, Globe, HardDrive, Home, Inbox, Info, KeyRound, Layers, LayoutGrid, List, ListFilter, Lock, LogOut, Mail, MailCheck, MapPin, Minus, Monitor, MousePointerClick, Pencil, Play, PlugZap, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Rows2, Rows3, Search, SearchX, Server, ServerCrash, Settings, ShieldCheck, SlidersHorizontal, Smartphone, Sparkles, Table2, Tablet, Trash2, TriangleAlert, Upload, User, UserMinus, UserPlus, Users, Workflow, Wrench, X, Zap } from "@gntik-ai/icons";
|
|
4
|
-
import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Breadcrumbs, Button, Card, CardAction, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, Collapsible, CollapsiblePanel, CollapsibleTrigger, CommandPalette, CommandPaletteTrigger, CopyButton, CursorPagination, DEFAULT_DATE_RANGE_PRESETS, DateRangePicker, DensityProvider, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, FieldDescription, FieldError, FieldLabel, Fieldset, FieldsetLegend, IconButton, Input, Link, LiveAnnouncer, Logo, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Meter, MoreMenu, NavList, NotificationsPopover, OtpInput, Pagination, PasswordInput, Progress, Radio, RadioGroup, ResizablePanel, ResizablePanelGroup, ResizeHandle, SecretField, Select, SelectContent, SelectItem, SelectTrigger, SimpleSelect, Skeleton, Slider, Sparkline, Spinner, StatusDot, StatusTag, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Textarea, ThemeCycleButton, ThemeSwitcher, Timestamp, Toggle, ToggleGroup, Token, TokenInput, Toolbar, ToolbarButton, ToolbarEnd, ToolbarInput, ToolbarSeparator, ToolbarStart, UserMenu, WizardLayout, WorkspaceSwitcher, buttonVariants, cn, nextSortDirection, tableVariants, toDate, useAnnounce, useDensity, useHasLiveAnnouncer, useI18n } from "@gntik-ai/ui";
|
|
4
|
+
import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Breadcrumbs, Button, Card, CardAction, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, Collapsible, CollapsiblePanel, CollapsibleTrigger, CommandPalette, CommandPaletteTrigger, CopyButton, CursorPagination, DEFAULT_DATE_RANGE_PRESETS, DateRangePicker, DensityProvider, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, FieldDescription, FieldError, FieldLabel, Fieldset, FieldsetLegend, IconButton, Input, Link, LiveAnnouncer, Logo, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Meter, MoreMenu, NavList, NotificationsPopover, OtpInput, Pagination, PasswordInput, Progress, Radio, RadioGroup, ResizablePanel, ResizablePanelGroup, ResizeHandle, SecretField, Select, SelectContent, SelectItem, SelectTrigger, SimpleSelect, Skeleton, Slider, Sparkline, Spinner, StatusDot, StatusTag, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Textarea, ThemeCycleButton, ThemeSwitcher, Timestamp, Toggle, ToggleGroup, Token, TokenInput, Toolbar, ToolbarButton, ToolbarEnd, ToolbarInput, ToolbarSeparator, ToolbarStart, UserMenu, WizardLayout, WorkspaceSwitcher, buttonVariants, cn, foldText, matchRanges, nextSortDirection, tableVariants, toDate, useAnnounce, useDensity, useHasLiveAnnouncer, useI18n, useOptionalI18n } from "@gntik-ai/ui";
|
|
5
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { AreaChart, BarChart, CHART_COLORS, DonutChart, Heatmap, LineChart, chartFmt } from "@gntik-ai/charts";
|
|
7
7
|
import { FLOW_TONES, FlowCanvas, KIND_CHIP, KindGlyph, useFlowState } from "@gntik-ai/flow";
|
|
@@ -5130,23 +5130,18 @@ const LEVEL_STYLE = {
|
|
|
5130
5130
|
}
|
|
5131
5131
|
};
|
|
5132
5132
|
/** Wraps case-insensitive matches of `query` in <mark>. */
|
|
5133
|
-
function highlight(text, query) {
|
|
5134
|
-
if (!query) return text;
|
|
5135
|
-
const lower = text.toLowerCase();
|
|
5136
|
-
const q = query.toLowerCase();
|
|
5133
|
+
function highlight(text, query, locale) {
|
|
5137
5134
|
const parts = [];
|
|
5138
5135
|
let from = 0;
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
if (at > from) parts.push(text.slice(from, at));
|
|
5136
|
+
for (const [start, end] of matchRanges(text, query, { locale })) {
|
|
5137
|
+
parts.push(text.slice(from, start));
|
|
5142
5138
|
parts.push(/* @__PURE__ */ jsx("mark", {
|
|
5143
5139
|
className: "rounded-sm bg-warning/30 text-foreground",
|
|
5144
|
-
children: text.slice(
|
|
5145
|
-
},
|
|
5146
|
-
from =
|
|
5147
|
-
at = lower.indexOf(q, from);
|
|
5140
|
+
children: text.slice(start, end)
|
|
5141
|
+
}, start));
|
|
5142
|
+
from = end;
|
|
5148
5143
|
}
|
|
5149
|
-
|
|
5144
|
+
parts.push(text.slice(from));
|
|
5150
5145
|
return parts;
|
|
5151
5146
|
}
|
|
5152
5147
|
function lineText(line) {
|
|
@@ -5158,6 +5153,7 @@ function lineText(line) {
|
|
|
5158
5153
|
* follow-tail and per-line copy.
|
|
5159
5154
|
*/
|
|
5160
5155
|
function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight = 24, overscan = 8, defaultLevels = LOG_LEVELS, defaultFollow = true, onCopyLine, onSelectLine, selectedLineId, announceLines = true, titleAs: TitleTag = "h3", className }) {
|
|
5156
|
+
const { locale } = useI18n();
|
|
5161
5157
|
const titleId = useId();
|
|
5162
5158
|
const viewport = useRef(null);
|
|
5163
5159
|
const copyTimer = useRef(void 0);
|
|
@@ -5176,13 +5172,19 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
|
|
|
5176
5172
|
for (const l of lines) c[l.level] += 1;
|
|
5177
5173
|
return c;
|
|
5178
5174
|
}, [lines]);
|
|
5175
|
+
const foldedLines = useMemo(() => lines.map((line) => ({
|
|
5176
|
+
line,
|
|
5177
|
+
message: foldText(line.message, locale),
|
|
5178
|
+
source: foldText(line.source ?? "", locale)
|
|
5179
|
+
})), [lines, locale]);
|
|
5179
5180
|
const visible = useMemo(() => {
|
|
5180
|
-
const q = query.trim()
|
|
5181
|
-
return
|
|
5181
|
+
const q = foldText(query.trim(), locale);
|
|
5182
|
+
return foldedLines.filter(({ line, message, source }) => levels.includes(line.level) && (!q || message.indexOf(q) !== -1 || source.indexOf(q) !== -1)).map(({ line }) => line);
|
|
5182
5183
|
}, [
|
|
5183
|
-
|
|
5184
|
+
foldedLines,
|
|
5184
5185
|
levels,
|
|
5185
|
-
query
|
|
5186
|
+
query,
|
|
5187
|
+
locale
|
|
5186
5188
|
]);
|
|
5187
5189
|
const total = visible.length * rowHeight;
|
|
5188
5190
|
const maxScroll = Math.max(0, total - height);
|
|
@@ -5298,13 +5300,13 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
|
|
|
5298
5300
|
className: "hidden shrink-0 text-muted-foreground sm:inline",
|
|
5299
5301
|
children: [
|
|
5300
5302
|
"[",
|
|
5301
|
-
highlight(line.source, query
|
|
5303
|
+
highlight(line.source, query, locale),
|
|
5302
5304
|
"]"
|
|
5303
5305
|
]
|
|
5304
5306
|
}),
|
|
5305
5307
|
/* @__PURE__ */ jsx("span", {
|
|
5306
5308
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
5307
|
-
children: highlight(line.message, query
|
|
5309
|
+
children: highlight(line.message, query, locale)
|
|
5308
5310
|
}),
|
|
5309
5311
|
onSelectLine && /* @__PURE__ */ jsx(IconButton, {
|
|
5310
5312
|
size: "sm",
|
|
@@ -10072,6 +10074,7 @@ const pageHeaderTabs = [
|
|
|
10072
10074
|
//#region src/page-chrome/PageHeader/PageHeader.tsx
|
|
10073
10075
|
/** Screen header: breadcrumb, title + status, description, meta row, actions and optional tabs. */
|
|
10074
10076
|
function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs, title = "Deployments", titleRef, description = "Every build and release of this project across its environments.", status = "active", statuses, meta = pageHeaderMeta, actions = pageHeaderActions, tabs = pageHeaderTabs, tab, defaultTab, onTabChange, className }) {
|
|
10077
|
+
const { t } = useI18n();
|
|
10075
10078
|
const explicitPrimary = actions.findIndex((a) => a.variant === "primary");
|
|
10076
10079
|
const primaryIndex = explicitPrimary >= 0 ? explicitPrimary : actions.length - 1;
|
|
10077
10080
|
const primary = actions[primaryIndex];
|
|
@@ -10150,7 +10153,7 @@ function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs,
|
|
|
10150
10153
|
onValueChange: (value) => onTabChange?.(String(value)),
|
|
10151
10154
|
className: "mt-5",
|
|
10152
10155
|
children: /* @__PURE__ */ jsx(TabsList, {
|
|
10153
|
-
"aria-label": "
|
|
10156
|
+
"aria-label": t("pageHeader.sections"),
|
|
10154
10157
|
className: "overflow-x-auto",
|
|
10155
10158
|
children: tabs.map((t) => /* @__PURE__ */ jsx(TabsTab, {
|
|
10156
10159
|
value: t.value,
|
|
@@ -10168,7 +10171,7 @@ const meta$45 = {
|
|
|
10168
10171
|
name: "Page header",
|
|
10169
10172
|
family: "page-chrome",
|
|
10170
10173
|
status: "beta",
|
|
10171
|
-
description: "Screen header with breadcrumb, title and status, description, meta row, actions that fold into a MoreMenu on small screens, and optional navigation tabs. titleRef targets the h1 for titleRef.current.focus(), adding tabIndex=-1 only when supplied so the title stays outside the Tab order. In a StatusLayout heading slot use as=\"div\" and disable breadcrumb, meta, tabs, actions, status and description fixtures; the slot supplies the page’s only h1.",
|
|
10174
|
+
description: "Screen header with breadcrumb, title and status, description, meta row, actions that fold into a MoreMenu on small screens, and optional navigation tabs. titleRef targets the h1 for titleRef.current.focus(), adding tabIndex=-1 only when supplied so the title stays outside the Tab order. In a StatusLayout heading slot use as=\"div\" and disable breadcrumb, meta, tabs, actions, status and description fixtures; the slot supplies the page’s only h1. The tablist name follows I18nProvider (en/es); the Spanish preview keeps caller content unchanged.",
|
|
10172
10175
|
uses: [
|
|
10173
10176
|
"Breadcrumbs",
|
|
10174
10177
|
"Button",
|
|
@@ -12420,11 +12423,23 @@ function toggleOne(id, selected) {
|
|
|
12420
12423
|
else next.add(id);
|
|
12421
12424
|
return next;
|
|
12422
12425
|
}
|
|
12423
|
-
/** Default cell text for a raw value. */
|
|
12424
|
-
function formatCell(value) {
|
|
12426
|
+
/** Default cell text for a raw value. Omitting options preserves the legacy output. */
|
|
12427
|
+
function formatCell(value, options) {
|
|
12425
12428
|
if (value == null) return "—";
|
|
12426
|
-
if (value instanceof Date)
|
|
12427
|
-
|
|
12429
|
+
if (value instanceof Date) {
|
|
12430
|
+
if (!options) return value.toLocaleDateString();
|
|
12431
|
+
if (Number.isNaN(value.getTime())) return "—";
|
|
12432
|
+
return new Intl.DateTimeFormat(options.locale, {
|
|
12433
|
+
year: "numeric",
|
|
12434
|
+
month: "numeric",
|
|
12435
|
+
day: "numeric"
|
|
12436
|
+
}).format(value);
|
|
12437
|
+
}
|
|
12438
|
+
if (typeof value === "boolean") return (options?.booleanLabels ?? ["Yes", "No"])[value ? 0 : 1];
|
|
12439
|
+
if (typeof value === "number" && Number.isFinite(value) && options?.locale !== void 0) {
|
|
12440
|
+
const decimal = new Intl.NumberFormat(options.locale).formatToParts(1.1).find((part) => part.type === "decimal");
|
|
12441
|
+
return String(value).replace(".", decimal?.value ?? ".");
|
|
12442
|
+
}
|
|
12428
12443
|
return value;
|
|
12429
12444
|
}
|
|
12430
12445
|
/** Group key of a row (`''` when the value is null or undefined). */
|
|
@@ -12667,6 +12682,7 @@ function isCellEditable(column, row) {
|
|
|
12667
12682
|
//#region src/tables/DataTable/data-table-row.tsx
|
|
12668
12683
|
function DataTableRow({ labels, row, columns, getRowId, getRowLabel, selectable, selected, singleSelection, onToggleRow, rowActions, layout, onCellEdit, editHintId, ariaRowIndex, style }) {
|
|
12669
12684
|
const { t } = useI18n();
|
|
12685
|
+
const locale = useOptionalI18n()?.locale;
|
|
12670
12686
|
const id = getRowId(row);
|
|
12671
12687
|
const selectionColumn = selectable || singleSelection != null;
|
|
12672
12688
|
const isSelected = singleSelection ? singleSelection.selectedId === id : selected.has(id);
|
|
@@ -12696,7 +12712,10 @@ function DataTableRow({ labels, row, columns, getRowId, getRowLabel, selectable,
|
|
|
12696
12712
|
}),
|
|
12697
12713
|
columns.map((c) => {
|
|
12698
12714
|
const cl = layout?.columns.get(c.id);
|
|
12699
|
-
const content = c.cell ? c.cell(row) : formatCell(c.accessor?.(row)
|
|
12715
|
+
const content = c.cell ? c.cell(row) : formatCell(c.accessor?.(row), {
|
|
12716
|
+
locale,
|
|
12717
|
+
booleanLabels: [labels?.booleanTrue ?? t("common.yes"), labels?.booleanFalse ?? t("common.no")]
|
|
12718
|
+
});
|
|
12700
12719
|
const editable = onCellEdit && editHintId && isCellEditable(c, row);
|
|
12701
12720
|
return /* @__PURE__ */ jsx(TableCell, {
|
|
12702
12721
|
align: columnAlign(c),
|
|
@@ -13922,6 +13941,16 @@ const meta$16 = {
|
|
|
13922
13941
|
status: "beta",
|
|
13923
13942
|
description: "Generic typed table: sortable headers with aria-sort, row selection with select-all and indeterminate by default (selectionMode=\"multiple\"), selectionMode=\"none\" to hide selection, column visibility menu, density toggle, row actions, loading and empty states, client-side sort and pagination, optional row groups (groupBy) with rowgroup header rows, counts, keyboard-accessible collapse buttons and group selection; column resize (pointer drag or a focusable role=\"separator\" handle with arrow keys, min/max widths, controlled columnWidths), column pinning to either edge with sticky cells (column menu or pinnedColumns), row virtualization for large datasets (aria-rowcount/aria-rowindex, works with selection and grouping), inline cell editing (text, number and select editors; Enter/F2 to edit, Enter/Tab to commit, Escape to cancel, onCellEdit can reject with an inline error) and saved views (filters, sort, visible columns, widths, pinning and grouping) with a view switcher to save as, rename, delete and reset. Opt-in selectionMode=\"single\" uses native radios in a labelled fieldset (never paginated or virtualized; paginated defaults to false and paginated=true is a type error). Single mode uses selectedId/onSelectedIdChange or defaultSelectedId; isRowDisabled skips unavailable rows and preserves a checked disabled choice without callbacks. Supply legend, aria-label or aria-labelledby for the group and getRowLabel for each radio (otherwise the first column labels it). selectionName is used verbatim and must be unique per page; omitted names use an instance-unique useId name, and duplicate supplied names or missing group labels warn in development. Tab enters once on the checked enabled row or first enabled row; arrows wrap and skip disabled rows, Space selects, Shift+Tab exits, and all-disabled groups have no tab stop. No select-all, group checkboxes, bulk actions or selection summary appear in single mode. Examples in examples/single-selection.tsx: an uncontrolled non-paginated list with legend=\"Available items\" and a controlled versions table with legend=\"Available versions\", selectedId=\"v2\" and a checked disabled version. Opt-in paginationMode=\"server\" accepts a controlled 1-based page, pageSize and required rowCount (known total), with onPageChange/onPageSizeChange requests. Supplied rows render in order without client sorting or slicing, and headers have no sort affordance. Single selection cannot use server mode. The footer stays visible for empty results, clamps stale pages for display without callbacks, and hides during loading. Page-size changes may also request a page to keep the first visible row on screen. The consumer owns fetching and reconciles stale pages. See examples/server-pagination.tsx for an items/total/page/pageSize envelope consumer that handles both callbacks.",
|
|
13924
13943
|
labels: [
|
|
13944
|
+
{
|
|
13945
|
+
key: "booleanTrue",
|
|
13946
|
+
type: "string",
|
|
13947
|
+
state: "Default cell text for a true boolean value"
|
|
13948
|
+
},
|
|
13949
|
+
{
|
|
13950
|
+
key: "booleanFalse",
|
|
13951
|
+
type: "string",
|
|
13952
|
+
state: "Default cell text for a false boolean value"
|
|
13953
|
+
},
|
|
13925
13954
|
{
|
|
13926
13955
|
key: "scrollRegion",
|
|
13927
13956
|
type: "string",
|