@tensor_1/react 2.5.0 → 2.6.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.
@@ -1,12 +1,26 @@
1
1
  import * as react from 'react';
2
2
  import { HTMLAttributes, ReactNode } from 'react';
3
3
 
4
+ type ShellNav = 'full' | 'rail' | 'hidden';
4
5
  interface AppShellProps extends HTMLAttributes<HTMLDivElement> {
6
+ /** Sidebar width tier: 'full' (default) → 'rail' (icon only) → 'hidden' (0). */
7
+ nav?: ShellNav;
8
+ /** Back-compat alias for nav="rail". Ignored when `nav` is set. */
5
9
  collapsed?: boolean;
10
+ /**
11
+ * Immersive focus mode: hides the sidebar AND the topbar so a wide, many-column
12
+ * table uses the whole frame. Provide `onExitFocus` to enable Esc-to-exit and
13
+ * the floating exit control.
14
+ */
15
+ focus?: boolean;
16
+ /** Called when the user presses Esc (or the exit control) while in focus mode. */
17
+ onExitFocus?: () => void;
18
+ /** Drop the content gutter so a genuinely wide table runs edge-to-edge. */
19
+ mainBleed?: boolean;
6
20
  sidebar?: ReactNode;
7
21
  topbar?: ReactNode;
8
22
  children?: ReactNode;
9
23
  }
10
- declare function AppShell({ collapsed, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
24
+ declare function AppShell({ nav, collapsed, focus, onExitFocus, mainBleed, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
11
25
 
12
- export { AppShell, type AppShellProps };
26
+ export { AppShell, type AppShellProps, type ShellNav };
@@ -1,11 +1,44 @@
1
+ "use client";
1
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect } from "react";
2
4
  import { cx } from "../cx.js";
3
- function AppShell({ collapsed, sidebar, topbar, children, className, ...props }) {
4
- return /* @__PURE__ */ jsxs("div", { className: cx("uix-shell", className), "data-collapsed": collapsed || void 0, ...props, children: [
5
- sidebar && /* @__PURE__ */ jsx("div", { className: "uix-shell__sidebar", children: sidebar }),
6
- topbar && /* @__PURE__ */ jsx("div", { className: "uix-shell__topbar", children: topbar }),
7
- /* @__PURE__ */ jsx("main", { className: "uix-shell__main", children })
8
- ] });
5
+ function AppShell({
6
+ nav,
7
+ collapsed,
8
+ focus,
9
+ onExitFocus,
10
+ mainBleed,
11
+ sidebar,
12
+ topbar,
13
+ children,
14
+ className,
15
+ ...props
16
+ }) {
17
+ const navState = nav ?? (collapsed ? "rail" : "full");
18
+ useEffect(() => {
19
+ if (!focus || !onExitFocus) return;
20
+ const onKey = (e) => {
21
+ if (e.key === "Escape") onExitFocus();
22
+ };
23
+ document.addEventListener("keydown", onKey);
24
+ return () => document.removeEventListener("keydown", onKey);
25
+ }, [focus, onExitFocus]);
26
+ return /* @__PURE__ */ jsxs(
27
+ "div",
28
+ {
29
+ className: cx("uix-shell", className),
30
+ "data-nav": navState !== "full" ? navState : void 0,
31
+ "data-collapsed": collapsed && nav == null ? "" : void 0,
32
+ "data-focus": focus || void 0,
33
+ ...props,
34
+ children: [
35
+ sidebar && /* @__PURE__ */ jsx("div", { className: "uix-shell__sidebar", children: sidebar }),
36
+ topbar && /* @__PURE__ */ jsx("div", { className: "uix-shell__topbar", children: topbar }),
37
+ /* @__PURE__ */ jsx("main", { className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
38
+ focus && onExitFocus && /* @__PURE__ */ jsx("div", { className: "uix-shell__focus-exit", children: /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: onExitFocus, children: "Esc \xB7 Exit focus" }) })
39
+ ]
40
+ }
41
+ );
9
42
  }
10
43
  export {
11
44
  AppShell
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface ComposerProps extends HTMLAttributes<HTMLDivElement> {
5
+ children?: ReactNode;
6
+ }
7
+ /**
8
+ * Composer surface over `.uix-composer` — a single box that owns the
9
+ * `:focus-within` accent ring. Drop a borderless `<textarea>` and a
10
+ * `<ComposerBar>` inside; the descendant `textarea` picks up the composer's
11
+ * padding/typography automatically, so the input never reads as a second
12
+ * nested box.
13
+ */
14
+ declare function Composer({ children, className, ...props }: ComposerProps): react.JSX.Element;
15
+ interface ComposerBarProps extends HTMLAttributes<HTMLDivElement> {
16
+ children?: ReactNode;
17
+ }
18
+ /** Action footer for a `<Composer>` over `.uix-composer__bar` (top-bordered, right-aligned). */
19
+ declare function ComposerBar({ children, className, ...props }: ComposerBarProps): react.JSX.Element;
20
+
21
+ export { Composer, ComposerBar, type ComposerBarProps, type ComposerProps };
@@ -0,0 +1,12 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cx } from "../cx.js";
3
+ function Composer({ children, className, ...props }) {
4
+ return /* @__PURE__ */ jsx("div", { className: cx("uix-composer", className), ...props, children });
5
+ }
6
+ function ComposerBar({ children, className, ...props }) {
7
+ return /* @__PURE__ */ jsx("div", { className: cx("uix-composer__bar", className), ...props, children });
8
+ }
9
+ export {
10
+ Composer,
11
+ ComposerBar
12
+ };
@@ -0,0 +1,29 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode, ButtonHTMLAttributes } from 'react';
3
+
4
+ interface SegmentedProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
5
+ /** The currently-selected option value. */
6
+ value?: string;
7
+ /** Fires with the option's value when a different option is chosen. */
8
+ onChange?: (value: string) => void;
9
+ children?: ReactNode;
10
+ }
11
+ /**
12
+ * Segmented single-select over `.uix-segmented` — the compact 2–3 way toggle
13
+ * (density, audience, view mode …) that reads as one pill with a lifted active
14
+ * segment. Selection state is shared with `<SegmentedOption>` via context, so
15
+ * the caller only wires `value` + `onChange` once.
16
+ */
17
+ declare function Segmented({ value, onChange, children, className, ...props }: SegmentedProps): react.JSX.Element;
18
+ interface SegmentedOptionProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {
19
+ value: string;
20
+ children?: ReactNode;
21
+ }
22
+ /**
23
+ * One option in a `<Segmented>`. Active state is derived from the parent's
24
+ * `value`; the pressed segment lifts to the surface via
25
+ * `.uix-segmented__option[aria-pressed="true"]`.
26
+ */
27
+ declare function SegmentedOption({ value, children, className, onClick, ...props }: SegmentedOptionProps): react.JSX.Element;
28
+
29
+ export { Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps };
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext } from "react";
4
+ import { cx } from "../cx.js";
5
+ const SegmentedCtx = createContext({});
6
+ function Segmented({ value, onChange, children, className, ...props }) {
7
+ return /* @__PURE__ */ jsx(SegmentedCtx.Provider, { value: { value, onChange }, children: /* @__PURE__ */ jsx("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
8
+ }
9
+ function SegmentedOption({
10
+ value,
11
+ children,
12
+ className,
13
+ onClick,
14
+ ...props
15
+ }) {
16
+ const ctx = useContext(SegmentedCtx);
17
+ const selected = ctx.value === value;
18
+ return /* @__PURE__ */ jsx(
19
+ "button",
20
+ {
21
+ type: "button",
22
+ className: cx("uix-segmented__option", className),
23
+ "aria-pressed": selected,
24
+ onClick: (e) => {
25
+ ctx.onChange?.(value);
26
+ onClick?.(e);
27
+ },
28
+ ...props,
29
+ children
30
+ }
31
+ );
32
+ }
33
+ export {
34
+ Segmented,
35
+ SegmentedOption
36
+ };
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { TableHTMLAttributes, HTMLAttributes, ReactNode, TdHTMLAttributes, ThHTMLAttributes } from 'react';
2
+ import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, ThHTMLAttributes } from 'react';
3
3
 
4
4
  interface TableWrapProps extends HTMLAttributes<HTMLDivElement> {
5
5
  children?: ReactNode;
@@ -11,16 +11,20 @@ interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
11
11
  density?: TableDensity;
12
12
  zebra?: boolean;
13
13
  pinnedCol?: boolean;
14
+ /** table-layout: fixed — required for reliable column widths + primary-column truncation */
15
+ fixed?: boolean;
14
16
  rowPeek?: boolean;
15
17
  v2?: boolean;
16
18
  }
17
- declare function Table({ density, zebra, pinnedCol, rowPeek, v2, className, children, ...props }: TableProps): react.JSX.Element;
19
+ declare function Table({ density, zebra, pinnedCol, fixed, rowPeek, v2, className, children, ...props }: TableProps): react.JSX.Element;
18
20
  interface ThProps extends ThHTMLAttributes<HTMLTableCellElement> {
19
21
  sortable?: boolean;
20
22
  sortDirection?: SortDirection;
23
+ /** 1-based ordinal shown when this column is a secondary key in a multi-sort */
24
+ sortOrder?: number;
21
25
  onSort?: () => void;
22
26
  }
23
- declare function Th({ sortable, sortDirection, onSort, className, children, onClick, ...props }: ThProps): react.JSX.Element;
27
+ declare function Th({ sortable, sortDirection, sortOrder, onSort, className, children, onClick, ...props }: ThProps): react.JSX.Element;
24
28
  interface TdProps extends TdHTMLAttributes<HTMLTableCellElement> {
25
29
  pinned?: boolean;
26
30
  }
@@ -30,5 +34,42 @@ interface TrProps extends HTMLAttributes<HTMLTableRowElement> {
30
34
  pinned?: boolean;
31
35
  }
32
36
  declare function Tr({ selected, pinned, className, children, ...props }: TrProps): react.JSX.Element;
37
+ interface BulkBarProps extends HTMLAttributes<HTMLDivElement> {
38
+ /** number of selected rows, rendered as "N selected" */
39
+ count?: number;
40
+ children?: ReactNode;
41
+ }
42
+ /** Contextual action bar shown above the table when ≥1 row is selected. */
43
+ declare function BulkBar({ count, children, className, ...props }: BulkBarProps): react.JSX.Element;
44
+ interface RowActionsProps extends TdHTMLAttributes<HTMLTableCellElement> {
45
+ children?: ReactNode;
46
+ }
47
+ /** Trailing cell that holds the row's hover actions (kebab, quick actions). */
48
+ declare function RowActions({ children, className, ...props }: RowActionsProps): react.JSX.Element;
49
+ interface RowActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
50
+ children?: ReactNode;
51
+ }
52
+ /** A single hover-revealed row action button (icon inside). */
53
+ declare function RowAction({ children, className, type, ...props }: RowActionProps): react.JSX.Element;
54
+ interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
55
+ expanded?: boolean;
56
+ }
57
+ /** Chevron button that expands/collapses an inline detail row. */
58
+ declare function ExpandToggle({ expanded, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
59
+ /** Emphasised primary cell text. */
60
+ declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
61
+ /** Secondary line under a primary cell value (muted, meta size). */
62
+ declare function CellSub({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
63
+ interface MarkProps extends HTMLAttributes<HTMLElement> {
64
+ children?: ReactNode;
65
+ }
66
+ /** A search-match highlight span. */
67
+ declare function Mark({ children, className, ...props }: MarkProps): react.JSX.Element;
68
+ interface HighlightedProps {
69
+ text: string;
70
+ query: string;
71
+ }
72
+ /** Render `text` with case-insensitive matches of `query` wrapped in <mark>. */
73
+ declare function Highlighted({ text, query }: HighlightedProps): react.JSX.Element;
33
74
 
34
- export { type SortDirection, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Td, type TdProps, Th, type ThProps, Tr, type TrProps };
75
+ export { BulkBar, type BulkBarProps, CellStrong, CellSub, ExpandToggle, type ExpandToggleProps, Highlighted, type HighlightedProps, Mark, type MarkProps, RowAction, type RowActionProps, RowActions, type RowActionsProps, type SortDirection, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Td, type TdProps, Th, type ThProps, Tr, type TrProps };
@@ -1,5 +1,6 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cx } from "../cx.js";
3
+ import { highlightSegments } from "../table-engine.js";
3
4
  function TableWrap({ children, className, ...props }) {
4
5
  return /* @__PURE__ */ jsx("div", { className: cx("uix-table-wrap", className), ...props, children });
5
6
  }
@@ -7,6 +8,7 @@ function Table({
7
8
  density = "standard",
8
9
  zebra = true,
9
10
  pinnedCol,
11
+ fixed,
10
12
  rowPeek,
11
13
  v2,
12
14
  className,
@@ -16,7 +18,13 @@ function Table({
16
18
  return /* @__PURE__ */ jsx(
17
19
  "table",
18
20
  {
19
- className: cx("uix-table", !zebra && "uix-table--no-zebra", pinnedCol && "uix-table--pinned-col", className),
21
+ className: cx(
22
+ "uix-table",
23
+ !zebra && "uix-table--no-zebra",
24
+ pinnedCol && "uix-table--pinned-col",
25
+ fixed && "uix-table--fixed",
26
+ className
27
+ ),
20
28
  "data-density": density !== "standard" ? density : void 0,
21
29
  "data-uix-rowpeek": rowPeek || void 0,
22
30
  "data-uix-table-v2": v2 || void 0,
@@ -25,12 +33,13 @@ function Table({
25
33
  }
26
34
  );
27
35
  }
28
- function Th({ sortable, sortDirection, onSort, className, children, onClick, ...props }) {
36
+ function Th({ sortable, sortDirection, sortOrder, onSort, className, children, onClick, ...props }) {
29
37
  return /* @__PURE__ */ jsx(
30
38
  "th",
31
39
  {
32
40
  className,
33
41
  "data-sort": sortable || void 0,
42
+ "data-sort-order": sortOrder != null && sortOrder > 0 ? sortOrder : void 0,
34
43
  "aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
35
44
  onClick: sortable ? onSort ?? onClick : onClick,
36
45
  ...props,
@@ -53,7 +62,58 @@ function Tr({ selected, pinned, className, children, ...props }) {
53
62
  }
54
63
  );
55
64
  }
65
+ function BulkBar({ count, children, className, ...props }) {
66
+ return /* @__PURE__ */ jsxs("div", { className: cx("uix-bulkbar", className), role: "toolbar", "aria-label": "Bulk actions", ...props, children: [
67
+ count != null && /* @__PURE__ */ jsxs("span", { className: "uix-bulkbar__count", children: [
68
+ count,
69
+ " selected"
70
+ ] }),
71
+ /* @__PURE__ */ jsx("span", { className: "uix-bulkbar__spacer" }),
72
+ children
73
+ ] });
74
+ }
75
+ function RowActions({ children, className, ...props }) {
76
+ return /* @__PURE__ */ jsx("td", { className: cx("uix-table__actions", className), ...props, children });
77
+ }
78
+ function RowAction({ children, className, type = "button", ...props }) {
79
+ return /* @__PURE__ */ jsx("button", { type, className: cx("uix-rowact", className), ...props, children });
80
+ }
81
+ function ExpandToggle({ expanded, className, type = "button", ...props }) {
82
+ return /* @__PURE__ */ jsx(
83
+ "button",
84
+ {
85
+ type,
86
+ className: cx("uix-table__expand", className),
87
+ "aria-expanded": expanded,
88
+ "aria-label": expanded ? "Collapse row" : "Expand row",
89
+ ...props,
90
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" }) })
91
+ }
92
+ );
93
+ }
94
+ function CellStrong({ children, className, ...props }) {
95
+ return /* @__PURE__ */ jsx("span", { className: cx("uix-cell-strong", className), ...props, children });
96
+ }
97
+ function CellSub({ children, className, ...props }) {
98
+ return /* @__PURE__ */ jsx("span", { className: cx("uix-cell-sub", className), ...props, children });
99
+ }
100
+ function Mark({ children, className, ...props }) {
101
+ return /* @__PURE__ */ jsx("mark", { className: cx("uix-mark", className), ...props, children });
102
+ }
103
+ function Highlighted({ text, query }) {
104
+ return /* @__PURE__ */ jsx(Fragment, { children: highlightSegments(text, query).map(
105
+ (seg, i) => seg.match ? /* @__PURE__ */ jsx("mark", { className: "uix-mark", children: seg.text }, i) : /* @__PURE__ */ jsx("span", { children: seg.text }, i)
106
+ ) });
107
+ }
56
108
  export {
109
+ BulkBar,
110
+ CellStrong,
111
+ CellSub,
112
+ ExpandToggle,
113
+ Highlighted,
114
+ Mark,
115
+ RowAction,
116
+ RowActions,
57
117
  Table,
58
118
  TableWrap,
59
119
  Td,
@@ -7,10 +7,16 @@ interface TimelineProps extends HTMLAttributes<HTMLDivElement> {
7
7
  /** Activity timeline container over `.uix-timeline`. */
8
8
  declare function Timeline({ children, className, ...props }: TimelineProps): react.JSX.Element;
9
9
  interface TimelineItemProps extends HTMLAttributes<HTMLDivElement> {
10
+ /**
11
+ * Custom rail node — an icon puck, an avatar, a tinted dot. Defaults to the
12
+ * accent `.uix-timeline__node` dot. Supply this to make a heterogeneous feed
13
+ * (comments + audit events) read on one rail with per-row node semantics.
14
+ */
15
+ node?: ReactNode;
10
16
  meta?: ReactNode;
11
17
  children?: ReactNode;
12
18
  }
13
19
  /** A timeline entry over `.uix-timeline__item` (node + connecting line + body). */
14
- declare function TimelineItem({ meta, children, className, ...props }: TimelineItemProps): react.JSX.Element;
20
+ declare function TimelineItem({ node, meta, children, className, ...props }: TimelineItemProps): react.JSX.Element;
15
21
 
16
22
  export { Timeline, TimelineItem, type TimelineItemProps, type TimelineProps };
@@ -3,10 +3,10 @@ import { cx } from "../cx.js";
3
3
  function Timeline({ children, className, ...props }) {
4
4
  return /* @__PURE__ */ jsx("div", { className: cx("uix-timeline", className), ...props, children });
5
5
  }
6
- function TimelineItem({ meta, children, className, ...props }) {
6
+ function TimelineItem({ node, meta, children, className, ...props }) {
7
7
  return /* @__PURE__ */ jsxs("div", { className: cx("uix-timeline__item", className), ...props, children: [
8
8
  /* @__PURE__ */ jsxs("div", { className: "uix-timeline__rail", children: [
9
- /* @__PURE__ */ jsx("span", { className: "uix-timeline__node" }),
9
+ node ?? /* @__PURE__ */ jsx("span", { className: "uix-timeline__node" }),
10
10
  /* @__PURE__ */ jsx("span", { className: "uix-timeline__line" })
11
11
  ] }),
12
12
  /* @__PURE__ */ jsxs("div", { className: "uix-timeline__body", children: [
@@ -0,0 +1,50 @@
1
+ import { SortKey, ColumnFilter, SelectAllState, ViewState, Row } from '../table-engine.js';
2
+
3
+ interface UseTableOptions {
4
+ /** row field used as the stable id (selection / pinning). Default: 'id'. */
5
+ idField?: string;
6
+ initialSort?: SortKey[];
7
+ initialFilters?: ColumnFilter[];
8
+ initialQuery?: string;
9
+ /** restrict full-text search to these fields (default: all values). */
10
+ searchFields?: readonly string[];
11
+ /** ids kept present + hoisted regardless of filter/sort. */
12
+ initialPinned?: Iterable<string>;
13
+ }
14
+ interface UseTableResult<T> {
15
+ /** derived view: filter → search → sort, then pinned rows hoisted to the top. */
16
+ rows: T[];
17
+ sort: SortKey[];
18
+ filters: ColumnFilter[];
19
+ query: string;
20
+ selected: ReadonlySet<string>;
21
+ pinned: ReadonlySet<string>;
22
+ /** header select-all tri-state over the current derived rows. */
23
+ selectAll: SelectAllState;
24
+ /** cycle a column's sort; pass additive (⇧-click) to keep it as a secondary key. */
25
+ toggleSort: (field: string, additive?: boolean) => void;
26
+ setSort: (keys: SortKey[]) => void;
27
+ setFilters: (filters: ColumnFilter[]) => void;
28
+ setQuery: (query: string) => void;
29
+ isSelected: (id: string) => boolean;
30
+ toggleRow: (id: string) => void;
31
+ /** toggle every currently-visible row from the header checkbox. */
32
+ toggleAllRows: () => void;
33
+ clearSelection: () => void;
34
+ togglePin: (id: string) => void;
35
+ /** current state as a ViewState + its linkable query string. */
36
+ view: ViewState;
37
+ viewQueryString: string;
38
+ /** hydrate sort/filters/query from a saved-view query string. */
39
+ applyView: (queryString: string) => void;
40
+ }
41
+ /**
42
+ * Compose the framework-agnostic table-engine into React state: sorting, typed
43
+ * filtering, full-text search, page-scoped selection, pinning, and linkable saved
44
+ * views. Presentation stays in the `<Table>` primitives + table.css; this only owns
45
+ * the state and the derived row list. The vanilla styleguide (`guide/app.js`) runs
46
+ * the same engine functions, so both layers behave identically.
47
+ */
48
+ declare function useTable<T extends Row>(data: readonly T[], options?: UseTableOptions): UseTableResult<T>;
49
+
50
+ export { type UseTableOptions, type UseTableResult, useTable };
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { useCallback, useMemo, useState } from "react";
3
+ import {
4
+ multiSort,
5
+ toggleSort,
6
+ applyFilters,
7
+ searchRows,
8
+ serializeView,
9
+ parseView,
10
+ mergePinned,
11
+ toggleId,
12
+ togglePage,
13
+ selectAllState
14
+ } from "../table-engine.js";
15
+ function useTable(data, options = {}) {
16
+ const { idField = "id", searchFields } = options;
17
+ const [sort, setSort] = useState(() => options.initialSort ?? []);
18
+ const [filters, setFilters] = useState(() => options.initialFilters ?? []);
19
+ const [query, setQuery] = useState(() => options.initialQuery ?? "");
20
+ const [selected, setSelected] = useState(() => /* @__PURE__ */ new Set());
21
+ const [pinned, setPinned] = useState(() => new Set(options.initialPinned ?? []));
22
+ const rows = useMemo(() => {
23
+ const filtered = applyFilters(data, filters);
24
+ const searched = searchRows(filtered, query, searchFields);
25
+ const sorted = multiSort(searched, sort);
26
+ return mergePinned(data, sorted, pinned, idField);
27
+ }, [data, filters, query, searchFields, sort, pinned, idField]);
28
+ const pageIds = useMemo(() => rows.map((r) => String(r[idField])), [rows, idField]);
29
+ const selectAll = selectAllState(selected, pageIds);
30
+ const doToggleSort = useCallback((field, additive = false) => {
31
+ setSort((keys) => toggleSort(keys, field, additive));
32
+ }, []);
33
+ const toggleRow = useCallback((id) => setSelected((s) => toggleId(s, id)), []);
34
+ const toggleAllRows = useCallback(() => setSelected((s) => togglePage(s, pageIds)), [pageIds]);
35
+ const clearSelection = useCallback(() => setSelected(/* @__PURE__ */ new Set()), []);
36
+ const togglePin = useCallback((id) => setPinned((s) => toggleId(s, id)), []);
37
+ const view = useMemo(() => ({ sort, filters, q: query }), [sort, filters, query]);
38
+ const viewQueryString = useMemo(() => serializeView(view), [view]);
39
+ const applyView = useCallback((queryString) => {
40
+ const v = parseView(queryString);
41
+ setSort(v.sort ?? []);
42
+ setFilters(v.filters ?? []);
43
+ setQuery(v.q ?? "");
44
+ }, []);
45
+ return {
46
+ rows,
47
+ sort,
48
+ filters,
49
+ query,
50
+ selected,
51
+ pinned,
52
+ selectAll,
53
+ toggleSort: doToggleSort,
54
+ setSort,
55
+ setFilters,
56
+ setQuery,
57
+ isSelected: (id) => selected.has(id),
58
+ toggleRow,
59
+ toggleAllRows,
60
+ clearSelection,
61
+ togglePin,
62
+ view,
63
+ viewQueryString,
64
+ applyView
65
+ };
66
+ }
67
+ export {
68
+ useTable
69
+ };