@nexub/react 8.3.0 → 8.4.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/accessibility.json +1 -1
- package/dist/components/Button/Button.d.ts +8 -0
- package/dist/components/Button/Button.js +2 -2
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/CommandPalette/CommandPalette.js +18 -10
- package/dist/components/DataTable/DataTable.js +6 -6
- package/dist/components/DatePicker/DatePicker.js +1 -1
- package/dist/components/FilterBuilder/FilterBuilder.js +2 -2
- package/dist/components/Motion/ListTransition.js +2 -3
- package/dist/components/SavedViews/SavedViews.js +2 -2
- package/dist/components/Sortable/reorder.js +6 -1
- package/dist/index.d.ts +1 -1
- package/package.json +6 -6
package/accessibility.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "8.
|
|
2
|
+
"version": "8.4.0",
|
|
3
3
|
"standard": "WCAG 2.2 Level AA",
|
|
4
4
|
"method": {
|
|
5
5
|
"automated": "axe-core rules tagged wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa, run on every Storybook story in light and dark, and on open popups (menus, listboxes, dialogs), on every pull request; a new violation fails the build.",
|
|
@@ -9,7 +9,15 @@ export declare const buttonVariants: (props?: ({
|
|
|
9
9
|
fullWidth?: boolean | null | undefined;
|
|
10
10
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
11
11
|
export type ButtonStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated 8.4: the 1.x variant names, removed in 9.0. Use filled, tonal, outlined, text
|
|
14
|
+
* (`npx nexub-migrate --rules button-aliases --write`).
|
|
15
|
+
*/
|
|
16
|
+
export type ButtonLegacyVariant = 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
12
17
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
18
|
+
/** Visual style. primary, secondary, outline and ghost are deprecated aliases of
|
|
19
|
+
* filled, tonal, outlined and text, removed in 9.0. @default 'filled' */
|
|
20
|
+
variant?: VariantProps<typeof buttonVariants>['variant'];
|
|
13
21
|
tone?: ToneValue;
|
|
14
22
|
/** Async feedback. `loading` blocks clicks (aria-disabled, focus kept),
|
|
15
23
|
* `success` draws a check, `error` shakes once. Not applied with `asChild`. */
|
|
@@ -62,7 +62,7 @@ const buttonVariants = cva(
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
defaultVariants: {
|
|
65
|
-
variant: "
|
|
65
|
+
variant: "filled",
|
|
66
66
|
size: "md"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -121,7 +121,7 @@ const Button = React.forwardRef(
|
|
|
121
121
|
onPointerMove: handlePointerMove,
|
|
122
122
|
"data-tone": tone,
|
|
123
123
|
// Styling hook for opt-in layers (vivid, marketing); no styles depend on it by default.
|
|
124
|
-
"data-variant": variant ?? "
|
|
124
|
+
"data-variant": variant ?? "filled",
|
|
125
125
|
...variant === "glass" && { "data-material": "glass", "data-glass-thickness": "thin" },
|
|
126
126
|
...props
|
|
127
127
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Button, buttonVariants } from './Button.js';
|
|
2
|
-
export type { ButtonProps, ButtonStatus, ToneValue } from './Button.js';
|
|
2
|
+
export type { ButtonProps, ButtonStatus, ButtonLegacyVariant, ToneValue } from './Button.js';
|
|
@@ -49,20 +49,27 @@ const Root = React.forwardRef(
|
|
|
49
49
|
const messages = useNexubMessages();
|
|
50
50
|
const [pages = [], setPages] = useControllableState({ value: pagesProp, defaultValue: defaultPages, onChange: onPagesChange });
|
|
51
51
|
const [open = false, setOpenState] = useControllableState({ value: openProp, defaultValue: defaultOpen, onChange: onOpenChange });
|
|
52
|
-
const setOpen = (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const setOpen = React.useCallback(
|
|
53
|
+
(next) => {
|
|
54
|
+
setOpenState(next);
|
|
55
|
+
if (!next && pages.length) setPages([]);
|
|
56
|
+
},
|
|
57
|
+
[setOpenState, setPages, pages.length]
|
|
58
|
+
);
|
|
56
59
|
const [titles, setTitles] = React.useState({});
|
|
57
60
|
const [recents, setRecents] = React.useState([]);
|
|
58
61
|
const handlers = React.useRef(/* @__PURE__ */ new Map()).current;
|
|
62
|
+
const setTitle = React.useCallback(
|
|
63
|
+
(page, title) => setTitles((t) => t[page] === title ? t : { ...t, [page]: title }),
|
|
64
|
+
[]
|
|
65
|
+
);
|
|
59
66
|
React.useEffect(() => setRecents(recentKey ? readRecents(recentKey) : []), [recentKey]);
|
|
60
67
|
const ctx = {
|
|
61
68
|
pages,
|
|
62
69
|
push: (page) => setPages([...pages, page]),
|
|
63
70
|
pop: () => setPages(pages.slice(0, -1)),
|
|
64
71
|
titles,
|
|
65
|
-
setTitle
|
|
72
|
+
setTitle,
|
|
66
73
|
loading,
|
|
67
74
|
recents,
|
|
68
75
|
record: (recent) => {
|
|
@@ -132,11 +139,12 @@ const Input = React.forwardRef(({ className, value: valueProp, onValueChange, on
|
|
|
132
139
|
const pages = palette?.pages ?? [];
|
|
133
140
|
const [value = "", setValue] = useControllableState({ value: valueProp, defaultValue: "", onChange: onValueChange });
|
|
134
141
|
const depth = pages.length;
|
|
135
|
-
const
|
|
142
|
+
const shownDepth = React.useRef(depth);
|
|
136
143
|
React.useEffect(() => {
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
if (shownDepth.current === depth) return;
|
|
145
|
+
shownDepth.current = depth;
|
|
146
|
+
setValue("");
|
|
147
|
+
}, [depth, setValue]);
|
|
140
148
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 border-b border-[var(--color-outline-variant)] px-3", children: [
|
|
141
149
|
/* @__PURE__ */ jsx(Search, { size: "sm", className: "me-1 shrink-0 opacity-50", "aria-hidden": "true" }),
|
|
142
150
|
pages.map((page) => /* @__PURE__ */ jsx(Badge, { variant: "soft", size: "sm", className: "shrink-0", children: palette?.titles[page] ?? page }, page)),
|
|
@@ -271,7 +279,7 @@ function Page({ id, title, children }) {
|
|
|
271
279
|
const setTitle = palette?.setTitle;
|
|
272
280
|
useIsomorphicLayoutEffect(() => {
|
|
273
281
|
if (id && title) setTitle?.(id, title);
|
|
274
|
-
}, [id, title]);
|
|
282
|
+
}, [id, title, setTitle]);
|
|
275
283
|
const pages = palette?.pages ?? [];
|
|
276
284
|
const active = id ? pages[pages.length - 1] === id : pages.length === 0;
|
|
277
285
|
return active ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
|
|
@@ -314,6 +314,8 @@ function DataTable({
|
|
|
314
314
|
() => withSelectColumn && pinningIn.left?.length && !pinningIn.left.includes("__select") ? { ...pinningIn, left: ["__select", ...pinningIn.left] } : pinningIn,
|
|
315
315
|
[withSelectColumn, pinningIn]
|
|
316
316
|
);
|
|
317
|
+
const rowReorderRef = React.useRef(rowReorder);
|
|
318
|
+
rowReorderRef.current = rowReorder;
|
|
317
319
|
const withRowHandles = React.useCallback(
|
|
318
320
|
(cols) => reorderRows ? [
|
|
319
321
|
{
|
|
@@ -321,13 +323,11 @@ function DataTable({
|
|
|
321
323
|
enableSorting: false,
|
|
322
324
|
enableHiding: false,
|
|
323
325
|
header: () => null,
|
|
324
|
-
cell: ({ row }) => row.depth === 0 ?
|
|
326
|
+
cell: ({ row }) => row.depth === 0 ? rowReorderRef.current.handle([0, row.index]) : null
|
|
325
327
|
},
|
|
326
328
|
...cols
|
|
327
329
|
] : cols,
|
|
328
|
-
|
|
329
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
330
|
-
[reorderRows, data]
|
|
330
|
+
[reorderRows]
|
|
331
331
|
);
|
|
332
332
|
const allColumns = React.useMemo(
|
|
333
333
|
() => withRowHandles(withSelectColumn ? [
|
|
@@ -436,7 +436,7 @@ function DataTable({
|
|
|
436
436
|
if (grid) gridNav.sync(t);
|
|
437
437
|
});
|
|
438
438
|
const visibleColumns = table.getVisibleLeafColumns();
|
|
439
|
-
const viewButton = /* @__PURE__ */ jsxs(Button, { variant: "
|
|
439
|
+
const viewButton = /* @__PURE__ */ jsxs(Button, { variant: "outlined", size: "sm", className: "ms-auto", children: [
|
|
440
440
|
/* @__PURE__ */ jsx(SlidersHorizontal, { size: "sm", "aria-hidden": "true" }),
|
|
441
441
|
messages.view
|
|
442
442
|
] });
|
|
@@ -670,7 +670,7 @@ function DataTable({
|
|
|
670
670
|
selectedRows.map((r) => r.original),
|
|
671
671
|
clear
|
|
672
672
|
),
|
|
673
|
-
/* @__PURE__ */ jsx(Button, { variant: "
|
|
673
|
+
/* @__PURE__ */ jsx(Button, { variant: "text", size: "sm", onClick: clear, "aria-label": messages.clearSelection, children: /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" }) })
|
|
674
674
|
]
|
|
675
675
|
}
|
|
676
676
|
)
|
|
@@ -215,7 +215,7 @@ const DatePicker = React.forwardRef(
|
|
|
215
215
|
...calendar.dayPickerProps
|
|
216
216
|
}
|
|
217
217
|
),
|
|
218
|
-
presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 border-t border-[var(--color-outline-variant)] p-2", children: presets.map((p) => /* @__PURE__ */ jsx(Button, { variant: "
|
|
218
|
+
presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 border-t border-[var(--color-outline-variant)] p-2", children: presets.map((p) => /* @__PURE__ */ jsx(Button, { variant: "text", size: "xs", onClick: () => pick(p.date), children: p.label }, p.label)) })
|
|
219
219
|
]
|
|
220
220
|
}
|
|
221
221
|
) })
|
|
@@ -82,14 +82,14 @@ function GroupView({ group, fields, depth, maxDepth, onChange, onRemove, classNa
|
|
|
82
82
|
return isFilterGroup(r) ? /* @__PURE__ */ jsx(GroupView, { group: r, fields, depth: depth + 1, maxDepth, onChange: replace, onRemove: remove }, r.id) : /* @__PURE__ */ jsx(RuleRow, { rule: r, fields, onChange: replace, onRemove: remove }, r.id);
|
|
83
83
|
}),
|
|
84
84
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
85
|
-
/* @__PURE__ */ jsxs(Button, { variant: "
|
|
85
|
+
/* @__PURE__ */ jsxs(Button, { variant: "text", size: "sm", onClick: () => setRules((rules) => [...rules, newRule()]), disabled: !first, children: [
|
|
86
86
|
/* @__PURE__ */ jsx(Plus, { size: "sm", "aria-hidden": "true" }),
|
|
87
87
|
t.addFilter
|
|
88
88
|
] }),
|
|
89
89
|
depth < maxDepth && /* @__PURE__ */ jsxs(
|
|
90
90
|
Button,
|
|
91
91
|
{
|
|
92
|
-
variant: "
|
|
92
|
+
variant: "text",
|
|
93
93
|
size: "sm",
|
|
94
94
|
onClick: () => setRules((rules) => [...rules, { id: uid(), combinator: "and", rules: [newRule()] }]),
|
|
95
95
|
disabled: !first,
|
|
@@ -53,10 +53,9 @@ const ListTransition = React.forwardRef(function ListTransition2({ as: Tag = "di
|
|
|
53
53
|
const exiting = rendered.filter((e) => e.state === "exit").map((e) => e.key).join("|");
|
|
54
54
|
React.useEffect(() => {
|
|
55
55
|
if (!exiting) return;
|
|
56
|
-
const
|
|
57
|
-
const t = setTimeout(() => keys.forEach(remove), EXIT_FALLBACK_MS);
|
|
56
|
+
const t = setTimeout(() => setEntries((list) => list.filter((e) => e.state !== "exit")), EXIT_FALLBACK_MS);
|
|
58
57
|
return () => clearTimeout(t);
|
|
59
|
-
}, [exiting
|
|
58
|
+
}, [exiting]);
|
|
60
59
|
return /* @__PURE__ */ jsx(Tag, { ref, ...rest, children: rendered.map((e) => /* @__PURE__ */ jsx(
|
|
61
60
|
Item,
|
|
62
61
|
{
|
|
@@ -14,7 +14,7 @@ function SavedViews({ views, activeId, onSelect, onSave, onUpdate, onDelete, cla
|
|
|
14
14
|
const active = views.find((v) => v.id === activeId);
|
|
15
15
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16
16
|
/* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
|
|
17
|
-
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "
|
|
17
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outlined", size: "sm", className, children: [
|
|
18
18
|
/* @__PURE__ */ jsx(Bookmark, { size: "sm", "aria-hidden": "true" }),
|
|
19
19
|
active?.name ?? t.views,
|
|
20
20
|
/* @__PURE__ */ jsx(ChevronDown, { size: "sm", "aria-hidden": "true" })
|
|
@@ -51,7 +51,7 @@ function SavedViews({ views, activeId, onSelect, onSave, onUpdate, onDelete, cla
|
|
|
51
51
|
/* @__PURE__ */ jsx(Dialog.Header, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: t.saveView.replace(/…$/, "") }) }),
|
|
52
52
|
/* @__PURE__ */ jsx(Input, { "aria-label": t.viewName, placeholder: t.viewName, value: name, onChange: (e) => setName(e.target.value), autoFocus: true }),
|
|
53
53
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
|
54
|
-
/* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "
|
|
54
|
+
/* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "text", children: t.cancel }) }),
|
|
55
55
|
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: !name.trim(), children: t.save })
|
|
56
56
|
] })
|
|
57
57
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect.js";
|
|
4
5
|
import { GripVertical } from "@nexub/icons";
|
|
5
6
|
import { cn } from "../../utils/cn.js";
|
|
6
7
|
import { useLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
@@ -152,7 +153,11 @@ function useReorder({ lists, getId, getLabel, listLabels, onMove }) {
|
|
|
152
153
|
setDragging(null);
|
|
153
154
|
setMark(null);
|
|
154
155
|
};
|
|
155
|
-
React.
|
|
156
|
+
const finishRef = React.useRef(finish);
|
|
157
|
+
useIsomorphicLayoutEffect(() => {
|
|
158
|
+
finishRef.current = finish;
|
|
159
|
+
});
|
|
160
|
+
React.useEffect(() => () => finishRef.current(false), []);
|
|
156
161
|
const begin = (d) => {
|
|
157
162
|
d.active = true;
|
|
158
163
|
d.el = itemOf(d.handle) ?? d.handle;
|
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export type { CitationProps, CitationSource, CitationMessages, SourceChipProps,
|
|
|
26
26
|
export { NexubProvider, useNexubMessages, useLocale, defaultMessages } from './components/NexubProvider/index.js';
|
|
27
27
|
export type { NexubProviderProps, NexubMessages, Direction as TextDirection } from './components/NexubProvider/index.js';
|
|
28
28
|
export { Button, buttonVariants } from './components/Button/index.js';
|
|
29
|
-
export type { ButtonProps, ButtonStatus, ToneValue } from './components/Button/index.js';
|
|
29
|
+
export type { ButtonProps, ButtonStatus, ButtonLegacyVariant, ToneValue } from './components/Button/index.js';
|
|
30
30
|
export { ButtonGroup } from './components/ButtonGroup/index.js';
|
|
31
31
|
export type { ButtonGroupProps } from './components/ButtonGroup/index.js';
|
|
32
32
|
export { SplitButton } from './components/SplitButton/index.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexub/react",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"description": "React component library for Nexub Design System — 90+ accessible, themeable UI components built on Radix UI primitives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -86,14 +86,14 @@
|
|
|
86
86
|
"get-nonce": "^1.0.1",
|
|
87
87
|
"react-day-picker": "^10.0.2",
|
|
88
88
|
"tailwind-merge": "^3.7.0",
|
|
89
|
-
"@nexub/core": "8.
|
|
90
|
-
"@nexub/icons": "8.
|
|
89
|
+
"@nexub/core": "8.4.0",
|
|
90
|
+
"@nexub/icons": "8.4.0"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
93
|
"react": ">=19 <20",
|
|
94
94
|
"react-dom": ">=19 <20",
|
|
95
95
|
"@tanstack/react-virtual": "^3.14.22",
|
|
96
|
-
"@nexub/tokens": "^8.
|
|
96
|
+
"@nexub/tokens": "^8.4.0"
|
|
97
97
|
},
|
|
98
98
|
"peerDependenciesMeta": {
|
|
99
99
|
"@tanstack/react-virtual": {
|
|
@@ -126,8 +126,8 @@
|
|
|
126
126
|
"vaul": "1.1.2",
|
|
127
127
|
"vite": "^8.3.5",
|
|
128
128
|
"vitest": "^5.0.5",
|
|
129
|
-
"@nexub/themes": "8.
|
|
130
|
-
"@nexub/tokens": "8.
|
|
129
|
+
"@nexub/themes": "8.4.0",
|
|
130
|
+
"@nexub/tokens": "8.4.0"
|
|
131
131
|
},
|
|
132
132
|
"scripts": {
|
|
133
133
|
"build": "rm -rf dist && tsup && tsc -p tsconfig.build.json && rm -f dist/vendor/*.d.ts && node scripts/check-dts.mjs && tailwindcss -i src/styles.css -o dist/styles.css --minify && cp -R ../themes/src/fonts dist/fonts",
|