@tensor_1/react 2.5.0 → 2.7.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/components/AppShell.d.ts +16 -2
- package/dist/components/AppShell.js +39 -6
- package/dist/components/Composer.d.ts +21 -0
- package/dist/components/Composer.js +12 -0
- package/dist/components/Field.js +10 -4
- package/dist/components/Popover.d.ts +18 -4
- package/dist/components/Popover.js +31 -2
- package/dist/components/Segmented.d.ts +29 -0
- package/dist/components/Segmented.js +36 -0
- package/dist/components/Table.d.ts +45 -4
- package/dist/components/Table.js +63 -3
- package/dist/components/Timeline.d.ts +7 -1
- package/dist/components/Timeline.js +2 -2
- package/dist/components/Toast.js +5 -4
- package/dist/components/Tooltip.d.ts +9 -5
- package/dist/components/Tooltip.js +61 -3
- package/dist/components/Tree.d.ts +15 -1
- package/dist/components/Tree.js +247 -35
- package/dist/hooks/useAnchoredPosition.d.ts +22 -0
- package/dist/hooks/useAnchoredPosition.js +44 -0
- package/dist/hooks/useDialog.js +36 -5
- package/dist/hooks/useTable.d.ts +50 -0
- package/dist/hooks/useTable.js +69 -0
- package/dist/index.cjs +1107 -141
- package/dist/index.d.cts +406 -15
- package/dist/index.d.ts +9 -2
- package/dist/index.js +40 -2
- package/dist/overlay-position.d.ts +59 -0
- package/dist/overlay-position.js +62 -0
- package/dist/table-engine.d.ts +89 -0
- package/dist/table-engine.js +251 -0
- package/dist/tree-model.d.ts +48 -0
- package/dist/tree-model.js +49 -0
- package/package.json +3 -2
|
@@ -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({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
};
|
package/dist/components/Field.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, isValidElement, useId } from "react";
|
|
2
3
|
import { cx } from "../cx.js";
|
|
3
4
|
function Field({ label, hint, error, success, required, children, className, htmlFor }) {
|
|
5
|
+
const uid = useId();
|
|
6
|
+
const msgId = `${uid}-msg`;
|
|
7
|
+
const describedBy = error || success || hint ? msgId : void 0;
|
|
8
|
+
const control = isValidElement(children) ? cloneElement(children, {
|
|
9
|
+
"aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0,
|
|
10
|
+
"aria-invalid": error ? true : children.props["aria-invalid"]
|
|
11
|
+
}) : children;
|
|
4
12
|
return /* @__PURE__ */ jsxs("div", { className: cx("uix-field", className), children: [
|
|
5
13
|
label && /* @__PURE__ */ jsx("label", { className: "uix-field__label", htmlFor, "data-required": required || void 0, children: label }),
|
|
6
|
-
|
|
7
|
-
error
|
|
8
|
-
success && !error && /* @__PURE__ */ jsx("span", { className: "uix-field__success", children: success }),
|
|
9
|
-
hint && !error && !success && /* @__PURE__ */ jsx("span", { className: "uix-field__hint", children: hint })
|
|
14
|
+
control,
|
|
15
|
+
/* @__PURE__ */ jsx("div", { className: "uix-field__msg", id: msgId, children: error ? /* @__PURE__ */ jsx("span", { className: "uix-field__error", role: "alert", children: error }) : success ? /* @__PURE__ */ jsx("span", { className: "uix-field__success", children: success }) : hint ? /* @__PURE__ */ jsx("span", { className: "uix-field__hint", children: hint }) : null })
|
|
10
16
|
] });
|
|
11
17
|
}
|
|
12
18
|
export {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { HTMLAttributes, RefObject, ReactNode } from 'react';
|
|
3
|
+
import { Placement } from '../overlay-position.js';
|
|
3
4
|
|
|
4
5
|
interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
6
|
/**
|
|
@@ -7,12 +8,25 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
7
8
|
* wires to it via `popoverTarget={id}`. Pass `"manual"` to control open state yourself.
|
|
8
9
|
*/
|
|
9
10
|
popover?: 'auto' | 'manual';
|
|
11
|
+
/**
|
|
12
|
+
* Element (or ref) to anchor against. When set, the popover is placed with
|
|
13
|
+
* cross-browser JS positioning — flip when it won't fit, shift to stay on-screen —
|
|
14
|
+
* instead of relying on CSS `anchor()`, which is Chromium-only and detaches the
|
|
15
|
+
* popover from its trigger everywhere else. The native Popover API still provides
|
|
16
|
+
* the top layer (so it escapes `overflow` clipping) and light-dismiss.
|
|
17
|
+
*/
|
|
18
|
+
anchor?: RefObject<HTMLElement | null> | HTMLElement | null;
|
|
19
|
+
/** Preferred placement when `anchor` is set. Default `'bottom-start'`. */
|
|
20
|
+
placement?: Placement;
|
|
21
|
+
/** Gap between the trigger and the popover, in px. Default 6. */
|
|
22
|
+
offset?: number;
|
|
10
23
|
children?: ReactNode;
|
|
11
24
|
}
|
|
12
25
|
/**
|
|
13
|
-
* Anchored surface over `.uix-popover`, using the native Popover API.
|
|
14
|
-
*
|
|
26
|
+
* Anchored surface over `.uix-popover`, using the native Popover API. Compose ITSM
|
|
27
|
+
* things like a filter popover, menu, or rich select by putting controls inside.
|
|
28
|
+
* Pass `anchor` to get collision-aware, cross-browser placement (UIX-FIX-02).
|
|
15
29
|
*/
|
|
16
|
-
declare function Popover({ popover,
|
|
30
|
+
declare function Popover({ popover, anchor, placement, offset, className, children, ...props }: PopoverProps): react.JSX.Element;
|
|
17
31
|
|
|
18
32
|
export { Popover, type PopoverProps };
|
|
@@ -1,8 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
4
|
import { cx } from "../cx.js";
|
|
3
|
-
|
|
5
|
+
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
|
+
function Popover({
|
|
7
|
+
popover = "auto",
|
|
8
|
+
anchor,
|
|
9
|
+
placement = "bottom-start",
|
|
10
|
+
offset = 6,
|
|
11
|
+
className,
|
|
12
|
+
children,
|
|
13
|
+
...props
|
|
14
|
+
}) {
|
|
15
|
+
const ref = useRef(null);
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
4
17
|
const popoverAttr = { popover };
|
|
5
|
-
|
|
18
|
+
const reposition = useAnchoredPosition(anchor ?? null, ref, {
|
|
19
|
+
open: open && !!anchor,
|
|
20
|
+
placement,
|
|
21
|
+
offset
|
|
22
|
+
});
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const el = ref.current;
|
|
25
|
+
if (!el || !anchor) return;
|
|
26
|
+
const sync = () => {
|
|
27
|
+
const isOpen = el.matches(":popover-open");
|
|
28
|
+
if (isOpen) reposition();
|
|
29
|
+
setOpen(isOpen);
|
|
30
|
+
};
|
|
31
|
+
el.addEventListener("toggle", sync);
|
|
32
|
+
return () => el.removeEventListener("toggle", sync);
|
|
33
|
+
}, [anchor, reposition]);
|
|
34
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
|
|
6
35
|
}
|
|
7
36
|
export {
|
|
8
37
|
Popover
|
|
@@ -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 {
|
|
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 };
|
package/dist/components/Table.js
CHANGED
|
@@ -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(
|
|
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: [
|
package/dist/components/Toast.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
3
|
function Toast({ title, message, tone, icon, onClose, leaving, className, ...props }) {
|
|
4
|
+
const assertive = tone === "danger";
|
|
4
5
|
return /* @__PURE__ */ jsxs(
|
|
5
6
|
"div",
|
|
6
7
|
{
|
|
7
8
|
className: cx("uix-toast", tone && `uix-toast--${tone}`, className),
|
|
8
9
|
"data-leaving": leaving || void 0,
|
|
9
|
-
role: "status",
|
|
10
|
-
"aria-live": "polite",
|
|
10
|
+
role: assertive ? "alert" : "status",
|
|
11
|
+
"aria-live": assertive ? "assertive" : "polite",
|
|
11
12
|
...props,
|
|
12
13
|
children: [
|
|
13
|
-
icon && /* @__PURE__ */ jsx("div", { className: "uix-toast__icon", children: icon }),
|
|
14
|
+
icon && /* @__PURE__ */ jsx("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
|
|
14
15
|
/* @__PURE__ */ jsxs("div", { className: "uix-toast__body", children: [
|
|
15
16
|
title && /* @__PURE__ */ jsx("div", { className: "uix-toast__title", children: title }),
|
|
16
17
|
message && /* @__PURE__ */ jsx("div", { className: "uix-toast__msg", children: message })
|
|
@@ -21,7 +22,7 @@ function Toast({ title, message, tone, icon, onClose, leaving, className, ...pro
|
|
|
21
22
|
);
|
|
22
23
|
}
|
|
23
24
|
function Toaster({ children, className, ...props }) {
|
|
24
|
-
return /* @__PURE__ */ jsx("div", { className: cx("uix-toaster", className),
|
|
25
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-toaster", className), ...props, children });
|
|
25
26
|
}
|
|
26
27
|
export {
|
|
27
28
|
Toast,
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
import { Placement } from '../overlay-position.js';
|
|
3
4
|
|
|
4
5
|
interface TooltipProps extends HTMLAttributes<HTMLSpanElement> {
|
|
5
|
-
/** Tooltip text.
|
|
6
|
+
/** Tooltip text. */
|
|
6
7
|
label: string;
|
|
8
|
+
/** Preferred placement. Default `'top'`. */
|
|
9
|
+
placement?: Placement;
|
|
7
10
|
children?: ReactNode;
|
|
8
11
|
}
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
+
* Tooltip whose bubble renders in the top layer via the native Popover API, so it
|
|
14
|
+
* escapes any `overflow: hidden/scroll` ancestor that would clip the old CSS-only
|
|
15
|
+
* `[data-uix-tip]` tooltip (UIX-FIX-02). Positioned by the shared overlay engine
|
|
16
|
+
* (flip/shift), shown on hover and keyboard focus, dismissed on blur or Escape.
|
|
13
17
|
*/
|
|
14
|
-
declare function Tooltip({ label, children, ...props }: TooltipProps): react.JSX.Element;
|
|
18
|
+
declare function Tooltip({ label, placement, className, children, ...props }: TooltipProps): react.JSX.Element;
|
|
15
19
|
|
|
16
20
|
export { Tooltip, type TooltipProps };
|
|
@@ -1,6 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "../cx.js";
|
|
5
|
+
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
|
+
function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
7
|
+
const triggerRef = useRef(null);
|
|
8
|
+
const bubbleRef = useRef(null);
|
|
9
|
+
const [open, setOpen] = useState(false);
|
|
10
|
+
const id = useId();
|
|
11
|
+
useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
|
|
12
|
+
const show = () => {
|
|
13
|
+
const b = bubbleRef.current;
|
|
14
|
+
if (b && !b.matches(":popover-open")) {
|
|
15
|
+
try {
|
|
16
|
+
b.showPopover();
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
setOpen(true);
|
|
21
|
+
};
|
|
22
|
+
const hide = () => {
|
|
23
|
+
const b = bubbleRef.current;
|
|
24
|
+
if (b && b.matches(":popover-open")) {
|
|
25
|
+
try {
|
|
26
|
+
b.hidePopover();
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
setOpen(false);
|
|
31
|
+
};
|
|
32
|
+
useEffect(() => () => {
|
|
33
|
+
const b = bubbleRef.current;
|
|
34
|
+
if (b && b.matches(":popover-open")) {
|
|
35
|
+
try {
|
|
36
|
+
b.hidePopover();
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, []);
|
|
41
|
+
const bubbleAttr = { popover: "manual" };
|
|
42
|
+
return /* @__PURE__ */ jsxs(
|
|
43
|
+
"span",
|
|
44
|
+
{
|
|
45
|
+
ref: triggerRef,
|
|
46
|
+
className: cx("uix-tooltip", className),
|
|
47
|
+
"aria-describedby": id,
|
|
48
|
+
onMouseEnter: show,
|
|
49
|
+
onMouseLeave: hide,
|
|
50
|
+
onFocus: show,
|
|
51
|
+
onBlur: hide,
|
|
52
|
+
onKeyDown: (e) => {
|
|
53
|
+
if (e.key === "Escape") hide();
|
|
54
|
+
},
|
|
55
|
+
...props,
|
|
56
|
+
children: [
|
|
57
|
+
children,
|
|
58
|
+
/* @__PURE__ */ jsx("span", { ref: bubbleRef, id, role: "tooltip", className: "uix-tooltip__bubble", ...bubbleAttr, children: label })
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
);
|
|
4
62
|
}
|
|
5
63
|
export {
|
|
6
64
|
Tooltip
|
|
@@ -11,8 +11,11 @@ interface TreeNodeProps {
|
|
|
11
11
|
node: TreeNodeData;
|
|
12
12
|
expanded: Set<string>;
|
|
13
13
|
selected?: string;
|
|
14
|
+
selectable: boolean;
|
|
15
|
+
tabbableId?: string;
|
|
14
16
|
onToggle: (id: string) => void;
|
|
15
17
|
onSelect?: (id: string) => void;
|
|
18
|
+
onFocusNode: (id: string) => void;
|
|
16
19
|
level?: number;
|
|
17
20
|
}
|
|
18
21
|
interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' | 'onChange'> {
|
|
@@ -22,7 +25,18 @@ interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' |
|
|
|
22
25
|
selected?: string;
|
|
23
26
|
onToggle?: (id: string) => void;
|
|
24
27
|
onSelect?: (id: string) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Virtualize a large tree — render only the rows in view (UIX-FIX-05). Defaults to auto
|
|
30
|
+
* (on past the engine's `shouldVirtualize` threshold of visible rows). When on, the tree is
|
|
31
|
+
* flattened to a scrollable list of `maxHeight` with fixed-height rows; a11y is preserved via
|
|
32
|
+
* `aria-level` / `aria-setsize` / `aria-posinset` instead of nested `role="group"`s.
|
|
33
|
+
*/
|
|
34
|
+
virtualize?: boolean;
|
|
35
|
+
/** Fixed row height (px) used for virtualization. Default 32. */
|
|
36
|
+
rowHeight?: number;
|
|
37
|
+
/** Scroll-viewport height (px) when virtualizing. Default 384. */
|
|
38
|
+
maxHeight?: number;
|
|
25
39
|
}
|
|
26
|
-
declare function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected, onToggle, onSelect, className, ...props }: TreeProps): react.JSX.Element;
|
|
40
|
+
declare function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected, onToggle, onSelect, virtualize, rowHeight, maxHeight, className, ...props }: TreeProps): react.JSX.Element;
|
|
27
41
|
|
|
28
42
|
export { Tree, type TreeNodeData, type TreeNodeProps, type TreeProps };
|