@nexub/react 5.4.0 → 5.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.
- package/accessibility.json +34 -1
- package/dist/components/AlertDialog/AlertDialog.d.ts +17 -0
- package/dist/components/AlertDialog/AlertDialog.js +40 -5
- package/dist/components/AlertDialog/index.d.ts +1 -0
- package/dist/components/DateRangePicker/DateRangePicker.d.ts +17 -0
- package/dist/components/DateRangePicker/DateRangePicker.js +123 -71
- package/dist/components/DateRangePicker/index.d.ts +2 -1
- package/dist/components/DateRangePicker/index.js +3 -1
- package/dist/components/EmptyState/EmptyStatePreset.d.ts +14 -0
- package/dist/components/EmptyState/EmptyStatePreset.js +23 -0
- package/dist/components/EmptyState/index.d.ts +2 -0
- package/dist/components/EmptyState/index.js +3 -1
- package/dist/components/FileUpload/FileUpload.d.ts +10 -3
- package/dist/components/FileUpload/FileUpload.js +13 -4
- package/dist/components/FileUpload/index.d.ts +1 -1
- package/dist/components/FilterBuilder/FilterBuilder.d.ts +50 -0
- package/dist/components/FilterBuilder/FilterBuilder.js +164 -0
- package/dist/components/FilterBuilder/index.d.ts +2 -0
- package/dist/components/FilterBuilder/index.js +8 -0
- package/dist/components/OTPInput/OTPInput.d.ts +28 -0
- package/dist/components/OTPInput/OTPInput.js +107 -0
- package/dist/components/OTPInput/index.d.ts +2 -0
- package/dist/components/OTPInput/index.js +4 -0
- package/dist/components/SavedViews/SavedViews.d.ts +26 -0
- package/dist/components/SavedViews/SavedViews.js +65 -0
- package/dist/components/SavedViews/index.d.ts +2 -0
- package/dist/components/SavedViews/index.js +4 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +14 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Plus, X } from "@nexub/icons";
|
|
5
|
+
import { cn } from "../../utils/cn.js";
|
|
6
|
+
import { useControllableState } from "../../hooks/useControllableState.js";
|
|
7
|
+
import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
8
|
+
import { Button } from "../Button/Button.js";
|
|
9
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
10
|
+
import { Input } from "../Input/Input.js";
|
|
11
|
+
import { Select } from "../Select/Select.js";
|
|
12
|
+
import { SegmentedControl } from "../SegmentedControl/SegmentedControl.js";
|
|
13
|
+
const filterOperators = {
|
|
14
|
+
text: ["contains", "equals", "notEquals", "startsWith", "isEmpty"],
|
|
15
|
+
number: ["equals", "notEquals", "greaterThan", "lessThan"],
|
|
16
|
+
select: ["equals", "notEquals"],
|
|
17
|
+
date: ["equals", "before", "after"]
|
|
18
|
+
};
|
|
19
|
+
const isFilterGroup = (r) => "rules" in r;
|
|
20
|
+
let seq = 0;
|
|
21
|
+
const uid = () => `f${(++seq).toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
|
22
|
+
const emptyFilter = () => ({ id: uid(), combinator: "and", rules: [] });
|
|
23
|
+
function countFilters(group) {
|
|
24
|
+
return group.rules.reduce(
|
|
25
|
+
(n, r) => n + (isFilterGroup(r) ? countFilters(r) : r.operator === "isEmpty" || r.value !== "" ? 1 : 0),
|
|
26
|
+
0
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function FilterBuilder({ fields, value: valueProp, defaultValue, onValueChange, maxDepth = 1, className }) {
|
|
30
|
+
const [value = emptyFilter(), setValue] = useControllableState({
|
|
31
|
+
value: valueProp,
|
|
32
|
+
defaultValue: defaultValue ?? emptyFilter(),
|
|
33
|
+
onChange: onValueChange
|
|
34
|
+
});
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
GroupView,
|
|
37
|
+
{
|
|
38
|
+
group: value,
|
|
39
|
+
fields,
|
|
40
|
+
depth: 0,
|
|
41
|
+
maxDepth,
|
|
42
|
+
onChange: setValue,
|
|
43
|
+
className
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
FilterBuilder.displayName = "FilterBuilder";
|
|
48
|
+
function GroupView({ group, fields, depth, maxDepth, onChange, onRemove, className }) {
|
|
49
|
+
const t = useNexubMessages();
|
|
50
|
+
const first = fields[0];
|
|
51
|
+
const setRules = (rules) => onChange({ ...group, rules });
|
|
52
|
+
const newRule = () => ({
|
|
53
|
+
id: uid(),
|
|
54
|
+
field: first?.id ?? "",
|
|
55
|
+
operator: filterOperators[first?.type ?? "text"][0],
|
|
56
|
+
value: ""
|
|
57
|
+
});
|
|
58
|
+
return /* @__PURE__ */ jsxs(
|
|
59
|
+
"div",
|
|
60
|
+
{
|
|
61
|
+
role: "group",
|
|
62
|
+
"aria-label": t.filterGroup(group.combinator),
|
|
63
|
+
className: cn(
|
|
64
|
+
"flex flex-col gap-2",
|
|
65
|
+
depth > 0 && "rounded-shape-container border border-[var(--color-outline-variant)] p-3",
|
|
66
|
+
className
|
|
67
|
+
),
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
70
|
+
/* @__PURE__ */ jsxs(
|
|
71
|
+
SegmentedControl.Root,
|
|
72
|
+
{
|
|
73
|
+
size: "sm",
|
|
74
|
+
"aria-label": t.filterGroup(group.combinator),
|
|
75
|
+
value: group.combinator,
|
|
76
|
+
onValueChange: (v) => v && onChange({ ...group, combinator: v }),
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx(SegmentedControl.Item, { value: "and", children: t.matchAll }),
|
|
79
|
+
/* @__PURE__ */ jsx(SegmentedControl.Item, { value: "or", children: t.matchAny })
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
onRemove && /* @__PURE__ */ jsx(IconButton, { label: t.removeGroup, variant: "ghost", size: "sm", className: "ms-auto", onClick: onRemove, children: /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" }) })
|
|
84
|
+
] }),
|
|
85
|
+
group.rules.map((r, i) => {
|
|
86
|
+
const replace = (next) => setRules(group.rules.map((x, j) => j === i ? next : x));
|
|
87
|
+
const remove = () => setRules(group.rules.filter((_, j) => j !== i));
|
|
88
|
+
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);
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
91
|
+
/* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setRules([...group.rules, newRule()]), disabled: !first, children: [
|
|
92
|
+
/* @__PURE__ */ jsx(Plus, { size: "sm", "aria-hidden": "true" }),
|
|
93
|
+
t.addFilter
|
|
94
|
+
] }),
|
|
95
|
+
depth < maxDepth && /* @__PURE__ */ jsxs(
|
|
96
|
+
Button,
|
|
97
|
+
{
|
|
98
|
+
variant: "ghost",
|
|
99
|
+
size: "sm",
|
|
100
|
+
onClick: () => setRules([...group.rules, { id: uid(), combinator: "and", rules: [newRule()] }]),
|
|
101
|
+
disabled: !first,
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ jsx(Plus, { size: "sm", "aria-hidden": "true" }),
|
|
104
|
+
t.addGroup
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] })
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
function RuleRow({
|
|
114
|
+
rule,
|
|
115
|
+
fields,
|
|
116
|
+
onChange,
|
|
117
|
+
onRemove
|
|
118
|
+
}) {
|
|
119
|
+
const t = useNexubMessages();
|
|
120
|
+
const field = fields.find((f) => f.id === rule.field) ?? fields[0];
|
|
121
|
+
const ops = filterOperators[field?.type ?? "text"];
|
|
122
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
123
|
+
/* @__PURE__ */ jsxs(
|
|
124
|
+
Select.Root,
|
|
125
|
+
{
|
|
126
|
+
value: field?.id,
|
|
127
|
+
onValueChange: (id) => {
|
|
128
|
+
const f = fields.find((x) => x.id === id);
|
|
129
|
+
const nextOps = filterOperators[f?.type ?? "text"];
|
|
130
|
+
onChange({ ...rule, field: id, operator: nextOps.includes(rule.operator) ? rule.operator : nextOps[0], value: "" });
|
|
131
|
+
},
|
|
132
|
+
children: [
|
|
133
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": t.filterField, className: "w-auto min-w-36", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
134
|
+
/* @__PURE__ */ jsx(Select.Content, { children: fields.map((f) => /* @__PURE__ */ jsx(Select.Item, { value: f.id, children: f.label }, f.id)) })
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
/* @__PURE__ */ jsxs(Select.Root, { value: rule.operator, onValueChange: (op) => onChange({ ...rule, operator: op }), children: [
|
|
139
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": t.filterOperator, className: "w-auto min-w-32", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
140
|
+
/* @__PURE__ */ jsx(Select.Content, { children: ops.map((op) => /* @__PURE__ */ jsx(Select.Item, { value: op, children: t.filterOperators[op] }, op)) })
|
|
141
|
+
] }),
|
|
142
|
+
rule.operator !== "isEmpty" && (field?.type === "select" ? /* @__PURE__ */ jsxs(Select.Root, { value: rule.value || void 0, onValueChange: (v) => onChange({ ...rule, value: v }), children: [
|
|
143
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-label": t.filterValue, className: "w-auto min-w-36", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
144
|
+
/* @__PURE__ */ jsx(Select.Content, { children: field.options?.map((o) => /* @__PURE__ */ jsx(Select.Item, { value: o.value, children: o.label }, o.value)) })
|
|
145
|
+
] }) : /* @__PURE__ */ jsx(
|
|
146
|
+
Input,
|
|
147
|
+
{
|
|
148
|
+
"aria-label": t.filterValue,
|
|
149
|
+
type: field?.type === "number" ? "number" : field?.type === "date" ? "date" : "text",
|
|
150
|
+
value: rule.value,
|
|
151
|
+
onChange: (e) => onChange({ ...rule, value: e.target.value }),
|
|
152
|
+
wrapperClassName: "w-auto min-w-36 flex-1"
|
|
153
|
+
}
|
|
154
|
+
)),
|
|
155
|
+
/* @__PURE__ */ jsx(IconButton, { label: t.removeFilter, variant: "ghost", size: "sm", onClick: onRemove, children: /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" }) })
|
|
156
|
+
] });
|
|
157
|
+
}
|
|
158
|
+
export {
|
|
159
|
+
FilterBuilder,
|
|
160
|
+
countFilters,
|
|
161
|
+
emptyFilter,
|
|
162
|
+
filterOperators,
|
|
163
|
+
isFilterGroup
|
|
164
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface OTPInputProps {
|
|
3
|
+
/** Number of characters. Default 6. */
|
|
4
|
+
length?: number;
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onValueChange?: (value: string) => void;
|
|
8
|
+
/** Called once every box is filled. */
|
|
9
|
+
onComplete?: (value: string) => void;
|
|
10
|
+
/** `numeric` (default) accepts digits only; `alphanumeric` accepts letters too. */
|
|
11
|
+
mode?: 'numeric' | 'alphanumeric';
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
invalid?: boolean;
|
|
14
|
+
/** Group name; defaults to "Verification code". */
|
|
15
|
+
'aria-label'?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Submits with a form under this name. */
|
|
18
|
+
name?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* One box per character. Typing moves on, Backspace moves back, paste and
|
|
22
|
+
* the OS's one-time-code suggestion fill every box. The value has no gaps:
|
|
23
|
+
* focusing a box past the end jumps to the first empty one.
|
|
24
|
+
*/
|
|
25
|
+
export declare function OTPInput({ length, value: valueProp, defaultValue, onValueChange, onComplete, mode, disabled, invalid, 'aria-label': ariaLabel, className, name, }: OTPInputProps): React.JSX.Element;
|
|
26
|
+
export declare namespace OTPInput {
|
|
27
|
+
var displayName: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../../utils/cn.js";
|
|
5
|
+
import { field, fieldFocusVisible, fieldInvalid } from "../../utils/control.js";
|
|
6
|
+
import { useControllableState } from "../../hooks/useControllableState.js";
|
|
7
|
+
import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect.js";
|
|
8
|
+
import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
9
|
+
function OTPInput({
|
|
10
|
+
length = 6,
|
|
11
|
+
value: valueProp,
|
|
12
|
+
defaultValue,
|
|
13
|
+
onValueChange,
|
|
14
|
+
onComplete,
|
|
15
|
+
mode = "numeric",
|
|
16
|
+
disabled,
|
|
17
|
+
invalid,
|
|
18
|
+
"aria-label": ariaLabel,
|
|
19
|
+
className,
|
|
20
|
+
name
|
|
21
|
+
}) {
|
|
22
|
+
const t = useNexubMessages();
|
|
23
|
+
const [value = "", setValue] = useControllableState({
|
|
24
|
+
value: valueProp,
|
|
25
|
+
defaultValue: defaultValue ?? "",
|
|
26
|
+
onChange: onValueChange
|
|
27
|
+
});
|
|
28
|
+
const refs = React.useRef([]);
|
|
29
|
+
const filled = React.useRef(value.length);
|
|
30
|
+
useIsomorphicLayoutEffect(() => {
|
|
31
|
+
filled.current = value.length;
|
|
32
|
+
});
|
|
33
|
+
const clean = (s) => (s.match(mode === "numeric" ? /\d/g : /[a-z0-9]/gi) ?? []).join("");
|
|
34
|
+
const commit = (next) => {
|
|
35
|
+
const v = next.slice(0, length);
|
|
36
|
+
filled.current = v.length;
|
|
37
|
+
setValue(v);
|
|
38
|
+
if (v.length === length) onComplete?.(v);
|
|
39
|
+
};
|
|
40
|
+
const focus = (i) => refs.current[Math.max(0, Math.min(length - 1, i))]?.focus();
|
|
41
|
+
const writeAt = (i, chars) => {
|
|
42
|
+
commit(value.slice(0, i) + chars + value.slice(i + chars.length));
|
|
43
|
+
focus(i + chars.length);
|
|
44
|
+
};
|
|
45
|
+
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": ariaLabel ?? t.verificationCode, className: cn("flex gap-2", className), children: [
|
|
46
|
+
Array.from({ length }, (_, i) => /* @__PURE__ */ jsx(
|
|
47
|
+
"input",
|
|
48
|
+
{
|
|
49
|
+
ref: (el) => {
|
|
50
|
+
refs.current[i] = el;
|
|
51
|
+
},
|
|
52
|
+
"aria-label": t.codeDigit(i + 1, length),
|
|
53
|
+
autoComplete: i === 0 ? "one-time-code" : "off",
|
|
54
|
+
inputMode: mode === "numeric" ? "numeric" : "text",
|
|
55
|
+
pattern: mode === "numeric" ? "[0-9]*" : void 0,
|
|
56
|
+
maxLength: i === 0 ? length : 2,
|
|
57
|
+
disabled,
|
|
58
|
+
"aria-invalid": invalid || void 0,
|
|
59
|
+
value: value[i] ?? "",
|
|
60
|
+
onFocus: (e) => {
|
|
61
|
+
if (i > filled.current) focus(filled.current);
|
|
62
|
+
else e.target.select();
|
|
63
|
+
},
|
|
64
|
+
onChange: (e) => {
|
|
65
|
+
const raw = clean(e.target.value);
|
|
66
|
+
const typed = raw.length === 2 && value[i] && raw.startsWith(value[i]) ? raw.slice(1) : raw;
|
|
67
|
+
if (typed) writeAt(Math.min(i, value.length), typed);
|
|
68
|
+
},
|
|
69
|
+
onPaste: (e) => {
|
|
70
|
+
const pasted = clean(e.clipboardData.getData("text"));
|
|
71
|
+
if (!pasted) return;
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
writeAt(Math.min(i, value.length), pasted);
|
|
74
|
+
},
|
|
75
|
+
onKeyDown: (e) => {
|
|
76
|
+
if (e.key === "Backspace") {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
if (value[i]) commit(value.slice(0, i) + value.slice(i + 1));
|
|
79
|
+
else if (i > 0) {
|
|
80
|
+
commit(value.slice(0, i - 1) + value.slice(i));
|
|
81
|
+
focus(i - 1);
|
|
82
|
+
}
|
|
83
|
+
} else if (e.key === "ArrowLeft") {
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
focus(i - 1);
|
|
86
|
+
} else if (e.key === "ArrowRight") {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
focus(i + 1);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
className: cn(
|
|
92
|
+
field,
|
|
93
|
+
fieldFocusVisible,
|
|
94
|
+
invalid && fieldInvalid,
|
|
95
|
+
"h-12 w-10 text-center text-title-md tabular-nums",
|
|
96
|
+
"disabled:cursor-not-allowed disabled:border-[var(--color-outline-variant)] disabled:bg-[var(--color-surface-container-low)] disabled:text-[var(--color-text-disabled)]"
|
|
97
|
+
)
|
|
98
|
+
},
|
|
99
|
+
i
|
|
100
|
+
)),
|
|
101
|
+
name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
OTPInput.displayName = "OTPInput";
|
|
105
|
+
export {
|
|
106
|
+
OTPInput
|
|
107
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface SavedView {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SavedViewsProps {
|
|
7
|
+
views: SavedView[];
|
|
8
|
+
/** The view in use; its name shows on the button. */
|
|
9
|
+
activeId?: string;
|
|
10
|
+
onSelect: (id: string) => void;
|
|
11
|
+
/** "Save as new view…": asks for a name, then calls this. Your app stores the view. */
|
|
12
|
+
onSave?: (name: string) => void;
|
|
13
|
+
/** "Update ‹view›": overwrite the active view with the current filters. */
|
|
14
|
+
onUpdate?: (id: string) => void;
|
|
15
|
+
/** "Delete ‹view›": remove the active view. */
|
|
16
|
+
onDelete?: (id: string) => void;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A menu of saved filter views. UI only: your app keeps the views and what
|
|
21
|
+
* each one restores (filters, sort, columns).
|
|
22
|
+
*/
|
|
23
|
+
export declare function SavedViews({ views, activeId, onSelect, onSave, onUpdate, onDelete, className }: SavedViewsProps): React.JSX.Element;
|
|
24
|
+
export declare namespace SavedViews {
|
|
25
|
+
var displayName: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Bookmark, ChevronDown } from "@nexub/icons";
|
|
5
|
+
import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
6
|
+
import { Button } from "../Button/Button.js";
|
|
7
|
+
import { DropdownMenu } from "../DropdownMenu/DropdownMenu.js";
|
|
8
|
+
import { Dialog } from "../Dialog/Dialog.js";
|
|
9
|
+
import { Input } from "../Input/Input.js";
|
|
10
|
+
function SavedViews({ views, activeId, onSelect, onSave, onUpdate, onDelete, className }) {
|
|
11
|
+
const t = useNexubMessages();
|
|
12
|
+
const [naming, setNaming] = React.useState(false);
|
|
13
|
+
const [name, setName] = React.useState("");
|
|
14
|
+
const active = views.find((v) => v.id === activeId);
|
|
15
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
|
|
17
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className, children: [
|
|
18
|
+
/* @__PURE__ */ jsx(Bookmark, { size: "sm", "aria-hidden": "true" }),
|
|
19
|
+
active?.name ?? t.views,
|
|
20
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: "sm", "aria-hidden": "true" })
|
|
21
|
+
] }) }),
|
|
22
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "start", children: [
|
|
23
|
+
views.length > 0 && /* @__PURE__ */ jsx(DropdownMenu.RadioGroup, { value: activeId ?? "", onValueChange: onSelect, children: views.map((v) => /* @__PURE__ */ jsx(DropdownMenu.RadioItem, { value: v.id, children: v.name }, v.id)) }),
|
|
24
|
+
views.length > 0 && (onSave || active && (onUpdate || onDelete)) && /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
|
|
25
|
+
onSave && /* @__PURE__ */ jsx(
|
|
26
|
+
DropdownMenu.Item,
|
|
27
|
+
{
|
|
28
|
+
onSelect: () => {
|
|
29
|
+
setName("");
|
|
30
|
+
setNaming(true);
|
|
31
|
+
},
|
|
32
|
+
children: t.saveView
|
|
33
|
+
}
|
|
34
|
+
),
|
|
35
|
+
active && onUpdate && /* @__PURE__ */ jsx(DropdownMenu.Item, { onSelect: () => onUpdate(active.id), children: t.updateView(active.name) }),
|
|
36
|
+
active && onDelete && /* @__PURE__ */ jsx(DropdownMenu.Item, { onSelect: () => onDelete(active.id), className: "text-[var(--color-error)]", children: t.deleteView(active.name) })
|
|
37
|
+
] })
|
|
38
|
+
] }),
|
|
39
|
+
onSave && /* @__PURE__ */ jsx(Dialog.Root, { open: naming, onOpenChange: setNaming, children: /* @__PURE__ */ jsx(Dialog.Content, { className: "max-w-sm", children: /* @__PURE__ */ jsxs(
|
|
40
|
+
"form",
|
|
41
|
+
{
|
|
42
|
+
onSubmit: (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
const n = name.trim();
|
|
45
|
+
if (!n) return;
|
|
46
|
+
onSave(n);
|
|
47
|
+
setNaming(false);
|
|
48
|
+
},
|
|
49
|
+
className: "flex flex-col gap-4",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: t.saveView.replace(/…$/, "") }) }),
|
|
52
|
+
/* @__PURE__ */ jsx(Input, { "aria-label": t.viewName, placeholder: t.viewName, value: name, onChange: (e) => setName(e.target.value), autoFocus: true }),
|
|
53
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", children: t.cancel }) }),
|
|
55
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: !name.trim(), children: t.save })
|
|
56
|
+
] })
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
) }) })
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
SavedViews.displayName = "SavedViews";
|
|
63
|
+
export {
|
|
64
|
+
SavedViews
|
|
65
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -144,6 +144,7 @@ export { KeyboardShortcut } from './components/KeyboardShortcut/index.js';
|
|
|
144
144
|
export type { KeyboardShortcutProps } from './components/KeyboardShortcut/index.js';
|
|
145
145
|
export { Dialog } from './components/Dialog/index.js';
|
|
146
146
|
export { AlertDialog } from './components/AlertDialog/index.js';
|
|
147
|
+
export type { AlertDialogConfirmProps } from './components/AlertDialog/index.js';
|
|
147
148
|
export { Popover } from './components/Popover/index.js';
|
|
148
149
|
export { Tooltip } from './components/Tooltip/index.js';
|
|
149
150
|
export { Provider as TooltipProvider } from './components/Tooltip/index.js';
|
|
@@ -161,6 +162,10 @@ export { Combobox } from './components/Combobox/index.js';
|
|
|
161
162
|
export { Autocomplete } from './components/Autocomplete/index.js';
|
|
162
163
|
export type { AutocompleteOption, AutocompleteProps } from './components/Autocomplete/index.js';
|
|
163
164
|
export { MultiSelect } from './components/MultiSelect/index.js';
|
|
165
|
+
export { FilterBuilder, filterOperators, isFilterGroup, emptyFilter, countFilters } from './components/FilterBuilder/index.js';
|
|
166
|
+
export type { FilterBuilderProps, FilterField, FilterFieldType, FilterOperator, FilterRule, FilterGroup } from './components/FilterBuilder/index.js';
|
|
167
|
+
export { SavedViews } from './components/SavedViews/index.js';
|
|
168
|
+
export type { SavedViewsProps, SavedView } from './components/SavedViews/index.js';
|
|
164
169
|
export type { MultiSelectOption, MultiSelectProps } from './components/MultiSelect/index.js';
|
|
165
170
|
export { Switch } from './components/Switch/index.js';
|
|
166
171
|
export type { SwitchProps } from './components/Switch/index.js';
|
|
@@ -201,15 +206,19 @@ export type { CommandPaletteRootProps } from './components/CommandPalette/index.
|
|
|
201
206
|
export { Table } from './components/Table/index.js';
|
|
202
207
|
export { DataTable } from './components/DataTable/index.js';
|
|
203
208
|
export type { DataTableProps, DataTableDensity } from './components/DataTable/index.js';
|
|
204
|
-
export { EmptyState } from './components/EmptyState/index.js';
|
|
209
|
+
export { EmptyState, EmptyStatePreset } from './components/EmptyState/index.js';
|
|
210
|
+
export type { EmptyStatePresetProps, EmptyStateKind } from './components/EmptyState/index.js';
|
|
205
211
|
export { ErrorState } from './components/ErrorState/index.js';
|
|
206
212
|
export type { ErrorStateProps } from './components/ErrorState/index.js';
|
|
207
213
|
export { FileUpload, fileAccepted } from './components/FileUpload/index.js';
|
|
208
|
-
export type { FileUploadRootProps, FileRejection } from './components/FileUpload/index.js';
|
|
214
|
+
export type { FileUploadRootProps, FileUploadItemProps, FileRejection } from './components/FileUpload/index.js';
|
|
215
|
+
export { OTPInput } from './components/OTPInput/index.js';
|
|
216
|
+
export type { OTPInputProps } from './components/OTPInput/index.js';
|
|
209
217
|
export { DatePicker } from './components/DatePicker/index.js';
|
|
210
218
|
export type { DatePickerProps } from './components/DatePicker/index.js';
|
|
211
219
|
export { DateRangePicker } from './components/DateRangePicker/index.js';
|
|
212
|
-
export
|
|
220
|
+
export { todayIn } from './components/DateRangePicker/index.js';
|
|
221
|
+
export type { DateRangePickerProps, DateRange, DateRangePreset } from './components/DateRangePicker/index.js';
|
|
213
222
|
export { ThemeProvider, ThemeScript, useTheme } from './components/ThemeProvider/index.js';
|
|
214
223
|
export type { ThemeMode, GlassMode, ThemeContextValue, ThemeProviderProps, ThemeScriptProps } from './components/ThemeProvider/index.js';
|
|
215
224
|
export { Fade, Slide, Scale, Collapse, ListTransition, SkeletonSwap, usePrefersReducedMotion, Reveal, Float, Marquee } from './components/Motion/index.js';
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,8 @@ import { Select } from "./components/Select/index.js";
|
|
|
90
90
|
import { Combobox } from "./components/Combobox/index.js";
|
|
91
91
|
import { Autocomplete } from "./components/Autocomplete/index.js";
|
|
92
92
|
import { MultiSelect } from "./components/MultiSelect/index.js";
|
|
93
|
+
import { FilterBuilder, filterOperators, isFilterGroup, emptyFilter, countFilters } from "./components/FilterBuilder/index.js";
|
|
94
|
+
import { SavedViews } from "./components/SavedViews/index.js";
|
|
93
95
|
import { Switch } from "./components/Switch/index.js";
|
|
94
96
|
import { Checkbox } from "./components/Checkbox/index.js";
|
|
95
97
|
import { RadioGroup } from "./components/RadioGroup/index.js";
|
|
@@ -114,11 +116,13 @@ import { Pagination } from "./components/Pagination/index.js";
|
|
|
114
116
|
import { CommandPalette } from "./components/CommandPalette/index.js";
|
|
115
117
|
import { Table } from "./components/Table/index.js";
|
|
116
118
|
import { DataTable } from "./components/DataTable/index.js";
|
|
117
|
-
import { EmptyState } from "./components/EmptyState/index.js";
|
|
119
|
+
import { EmptyState, EmptyStatePreset } from "./components/EmptyState/index.js";
|
|
118
120
|
import { ErrorState } from "./components/ErrorState/index.js";
|
|
119
121
|
import { FileUpload, fileAccepted } from "./components/FileUpload/index.js";
|
|
122
|
+
import { OTPInput } from "./components/OTPInput/index.js";
|
|
120
123
|
import { DatePicker } from "./components/DatePicker/index.js";
|
|
121
124
|
import { DateRangePicker } from "./components/DateRangePicker/index.js";
|
|
125
|
+
import { todayIn } from "./components/DateRangePicker/index.js";
|
|
122
126
|
import { ThemeProvider, ThemeScript, useTheme } from "./components/ThemeProvider/index.js";
|
|
123
127
|
import { Fade, Slide, Scale, Collapse, ListTransition, SkeletonSwap, usePrefersReducedMotion, Reveal, Float, Marquee } from "./components/Motion/index.js";
|
|
124
128
|
export {
|
|
@@ -167,10 +171,12 @@ export {
|
|
|
167
171
|
Drawer,
|
|
168
172
|
DropdownMenu,
|
|
169
173
|
EmptyState,
|
|
174
|
+
EmptyStatePreset,
|
|
170
175
|
ErrorState,
|
|
171
176
|
EyebrowChip,
|
|
172
177
|
Fade,
|
|
173
178
|
FileUpload,
|
|
179
|
+
FilterBuilder,
|
|
174
180
|
FilterChip,
|
|
175
181
|
Flag,
|
|
176
182
|
Flex,
|
|
@@ -208,6 +214,7 @@ export {
|
|
|
208
214
|
NexubProvider,
|
|
209
215
|
NumberInput,
|
|
210
216
|
NumberTicker,
|
|
217
|
+
OTPInput,
|
|
211
218
|
PageHeader,
|
|
212
219
|
Pagination,
|
|
213
220
|
PasswordInput,
|
|
@@ -220,6 +227,7 @@ export {
|
|
|
220
227
|
RadioGroup,
|
|
221
228
|
Rating,
|
|
222
229
|
Reveal,
|
|
230
|
+
SavedViews,
|
|
223
231
|
Scale,
|
|
224
232
|
ScrollArea,
|
|
225
233
|
ScrollProgress,
|
|
@@ -271,13 +279,17 @@ export {
|
|
|
271
279
|
chipVariants,
|
|
272
280
|
cn,
|
|
273
281
|
containerVariants,
|
|
282
|
+
countFilters,
|
|
274
283
|
defaultMessageStrings,
|
|
275
284
|
defaultMessages,
|
|
285
|
+
emptyFilter,
|
|
276
286
|
fileAccepted,
|
|
287
|
+
filterOperators,
|
|
277
288
|
headingVariants,
|
|
278
289
|
iconButtonVariants,
|
|
279
290
|
inputVariants,
|
|
280
291
|
inputWrapperVariants,
|
|
292
|
+
isFilterGroup,
|
|
281
293
|
labelVariants,
|
|
282
294
|
linkVariants,
|
|
283
295
|
logoVariants,
|
|
@@ -295,6 +307,7 @@ export {
|
|
|
295
307
|
textVariants,
|
|
296
308
|
textareaVariants,
|
|
297
309
|
toast,
|
|
310
|
+
todayIn,
|
|
298
311
|
toggleVariants,
|
|
299
312
|
transitionName,
|
|
300
313
|
useControllableState,
|