@nexub/react 6.3.0 → 6.5.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.
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { GripVertical } from "@nexub/icons";
5
+ import { cn } from "../../utils/cn.js";
6
+ import { useLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
7
+ function moveItem(lists, [fc, fi], [tc, ti]) {
8
+ const next = lists.map((l) => [...l]);
9
+ const [item] = next[fc].splice(fi, 1);
10
+ if (item === void 0) return lists;
11
+ next[tc].splice(Math.min(ti, next[tc].length), 0, item);
12
+ return next;
13
+ }
14
+ function useReorder({ lists, getId, getLabel, listLabels, onMove }) {
15
+ const t = useNexubMessages();
16
+ const { dir } = useLocale();
17
+ const dragged = React.useRef(null);
18
+ const handles = React.useRef(/* @__PURE__ */ new Map());
19
+ const refocus = React.useRef(null);
20
+ const [announcement, setAnnouncement] = React.useState("");
21
+ const hintId = React.useId();
22
+ React.useEffect(() => {
23
+ if (refocus.current) handles.current.get(refocus.current)?.focus();
24
+ refocus.current = null;
25
+ });
26
+ const move = (from, to, keepFocus) => {
27
+ if (from[0] === to[0] && from[1] === to[1]) return;
28
+ const item = lists[from[0]][from[1]];
29
+ const next = moveItem(lists, from, to);
30
+ const [tc] = to;
31
+ const ti = next[tc].indexOf(item);
32
+ if (keepFocus) refocus.current = getId(item);
33
+ onMove(next);
34
+ const total = next[tc].length;
35
+ setAnnouncement(
36
+ from[0] !== tc && listLabels?.[tc] ? t.itemMovedToColumn(getLabel(item), listLabels[tc], ti + 1, total) : t.itemMoved(getLabel(item), ti + 1, total)
37
+ );
38
+ };
39
+ const itemProps = (pos) => ({
40
+ draggable: true,
41
+ onDragStart: (e) => {
42
+ dragged.current = pos;
43
+ e.dataTransfer.effectAllowed = "move";
44
+ },
45
+ onDragOver: (e) => {
46
+ if (dragged.current) e.preventDefault();
47
+ },
48
+ onDrop: (e) => {
49
+ e.preventDefault();
50
+ e.stopPropagation();
51
+ if (dragged.current) move(dragged.current, pos, false);
52
+ dragged.current = null;
53
+ },
54
+ onDragEnd: () => {
55
+ dragged.current = null;
56
+ }
57
+ });
58
+ const listProps = (list) => ({
59
+ onDragOver: (e) => {
60
+ if (dragged.current) e.preventDefault();
61
+ },
62
+ onDrop: (e) => {
63
+ e.preventDefault();
64
+ if (dragged.current) move(dragged.current, [list, lists[list].length], false);
65
+ dragged.current = null;
66
+ }
67
+ });
68
+ const handle = (pos, className) => {
69
+ const item = lists[pos[0]][pos[1]];
70
+ const id = getId(item);
71
+ return /* @__PURE__ */ jsx(
72
+ "button",
73
+ {
74
+ type: "button",
75
+ ref: (el) => {
76
+ if (el) handles.current.set(id, el);
77
+ else handles.current.delete(id);
78
+ },
79
+ "aria-label": t.moveItem(getLabel(item)),
80
+ "aria-describedby": hintId,
81
+ onKeyDown: (e) => {
82
+ if (!e.altKey) return;
83
+ const [c, i] = pos;
84
+ const sideways = lists.length > 1;
85
+ const toNext = dir === "rtl" ? "ArrowLeft" : "ArrowRight";
86
+ const toPrev = dir === "rtl" ? "ArrowRight" : "ArrowLeft";
87
+ let to = null;
88
+ if (e.key === "ArrowUp" && i > 0) to = [c, i - 1];
89
+ else if (e.key === "ArrowDown" && i < lists[c].length - 1) to = [c, i + 1];
90
+ else if (sideways && e.key === toNext && c < lists.length - 1) to = [c + 1, i];
91
+ else if (sideways && e.key === toPrev && c > 0) to = [c - 1, i];
92
+ if (!to) return;
93
+ e.preventDefault();
94
+ move(pos, to, true);
95
+ },
96
+ className: cn(
97
+ "inline-flex size-7 shrink-0 cursor-grab items-center justify-center rounded-shape-min text-[var(--color-on-surface-variant)]",
98
+ "hover:bg-[var(--color-surface-container-high)] active:cursor-grabbing",
99
+ className
100
+ ),
101
+ children: /* @__PURE__ */ jsx(GripVertical, { size: "sm", "aria-hidden": "true" })
102
+ }
103
+ );
104
+ };
105
+ const live = /* @__PURE__ */ jsxs(Fragment, { children: [
106
+ /* @__PURE__ */ jsx("span", { id: hintId, hidden: true, children: t.reorderHint }),
107
+ /* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", children: announcement })
108
+ ] });
109
+ return { itemProps, listProps, handle, live };
110
+ }
111
+ export {
112
+ moveItem,
113
+ useReorder
114
+ };
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ export interface StepperStep {
3
+ id: string;
4
+ label: string;
5
+ description?: string;
6
+ }
7
+ export interface StepperProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange'> {
8
+ steps: StepperStep[];
9
+ /** Index of the step being shown. */
10
+ current: number;
11
+ /** Indexes of finished steps. @default every step before `current` */
12
+ completed?: number[];
13
+ /**
14
+ * Makes steps clickable. Linear by default: finished steps, the current one
15
+ * and the first unfinished one can be reached; the rest wait.
16
+ */
17
+ onStepChange?: (index: number) => void;
18
+ /** Any step can be reached. */
19
+ nonLinear?: boolean;
20
+ /** @default 'horizontal' */
21
+ orientation?: 'horizontal' | 'vertical';
22
+ }
23
+ /**
24
+ * Progress through a multi-step flow. Validate each step (a `Form` per step
25
+ * works well) and move `current` forward from its submit.
26
+ */
27
+ export declare const Stepper: React.ForwardRefExoticComponent<StepperProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Check } from "@nexub/icons";
5
+ import { cn } from "../../utils/cn.js";
6
+ import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
7
+ const Stepper = React.forwardRef(function Stepper2({ steps, current, completed: completedProp, onStepChange, nonLinear = false, orientation = "horizontal", className, ...props }, ref) {
8
+ const t = useNexubMessages();
9
+ const completed = new Set(completedProp ?? steps.slice(0, current).map((_, i) => i));
10
+ const firstOpen = steps.findIndex((_, i) => !completed.has(i));
11
+ const vertical = orientation === "vertical";
12
+ return /* @__PURE__ */ jsx("nav", { ref, className, ...props, children: /* @__PURE__ */ jsx("ol", { className: cn("m-0 flex list-none p-0", vertical ? "flex-col" : "flex-row items-start"), children: steps.map((step, i) => {
13
+ const done = completed.has(i);
14
+ const isCurrent = i === current;
15
+ const reachable = Boolean(onStepChange) && !isCurrent && (nonLinear || done || i === firstOpen);
16
+ const marker = /* @__PURE__ */ jsx(
17
+ "span",
18
+ {
19
+ "aria-hidden": "true",
20
+ className: cn(
21
+ "inline-flex size-8 shrink-0 items-center justify-center rounded-full text-label-md font-semibold",
22
+ done && !isCurrent ? "bg-[var(--color-primary)] text-[var(--color-on-primary)]" : isCurrent ? "border-2 border-[var(--color-primary)] bg-[var(--color-surface)] text-[var(--color-primary)]" : "border-2 border-[var(--color-outline-variant)] bg-[var(--color-surface)] text-[var(--color-on-surface-muted)]"
23
+ ),
24
+ children: done && !isCurrent ? /* @__PURE__ */ jsx(Check, { size: "xs" }) : i + 1
25
+ }
26
+ );
27
+ const text = /* @__PURE__ */ jsxs("span", { className: cn("flex min-w-0 flex-col gap-0.5", vertical ? "items-start text-start" : "items-center text-center"), children: [
28
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
29
+ t.stepOf(i + 1, steps.length),
30
+ ":"
31
+ ] }),
32
+ " ",
33
+ /* @__PURE__ */ jsx("span", { className: cn("text-label-lg font-medium", isCurrent || done ? "text-[var(--color-on-surface)]" : "text-[var(--color-on-surface-muted)]"), children: step.label }),
34
+ done && /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
35
+ ", ",
36
+ t.stepCompleted
37
+ ] }),
38
+ step.description && /* @__PURE__ */ jsx("span", { className: "text-body-sm text-[var(--color-on-surface-muted)]", children: step.description })
39
+ ] });
40
+ const body = vertical ? /* @__PURE__ */ jsxs("span", { className: "flex gap-3", children: [
41
+ marker,
42
+ /* @__PURE__ */ jsx("span", { className: "pt-1", children: text })
43
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-center gap-2 text-center", children: [
44
+ marker,
45
+ text
46
+ ] });
47
+ return /* @__PURE__ */ jsx(
48
+ "li",
49
+ {
50
+ "aria-current": isCurrent ? "step" : void 0,
51
+ className: cn(
52
+ "relative flex",
53
+ vertical ? "pb-6 last:pb-0" : "flex-1 justify-center",
54
+ // Connector to the next step.
55
+ i < steps.length - 1 && (vertical ? "after:absolute after:start-4 after:top-9 after:bottom-1 after:w-px" : "after:absolute after:top-4 after:start-[calc(50%+1.25rem)] after:end-[calc(-50%+1.25rem)] after:h-px"),
56
+ i < steps.length - 1 && (done ? "after:bg-[var(--color-primary)]" : "after:bg-[var(--color-outline-variant)]")
57
+ ),
58
+ children: reachable ? /* @__PURE__ */ jsx(
59
+ "button",
60
+ {
61
+ type: "button",
62
+ onClick: () => onStepChange(i),
63
+ className: "rounded-shape-control p-1 hover:bg-[var(--color-surface-container-high)]",
64
+ children: body
65
+ }
66
+ ) : /* @__PURE__ */ jsx("span", { className: "p-1", children: body })
67
+ },
68
+ step.id
69
+ );
70
+ }) }) });
71
+ });
72
+ export {
73
+ Stepper
74
+ };
@@ -0,0 +1,2 @@
1
+ export { Stepper } from './Stepper.js';
2
+ export type { StepperProps, StepperStep } from './Stepper.js';
@@ -0,0 +1,4 @@
1
+ import { Stepper } from "./Stepper.js";
2
+ export {
3
+ Stepper
4
+ };
package/dist/index.d.ts CHANGED
@@ -228,6 +228,16 @@ export { EventCalendar } from './components/EventCalendar/index.js';
228
228
  export type { EventCalendarProps, EventCalendarView, CalendarEvent, EventTone } from './components/EventCalendar/index.js';
229
229
  export { TreeView } from './components/TreeView/index.js';
230
230
  export type { TreeViewProps, TreeNode } from './components/TreeView/index.js';
231
+ export { ResizablePanels } from './components/ResizablePanels/index.js';
232
+ export type { ResizablePanelsProps } from './components/ResizablePanels/index.js';
233
+ export { Stepper } from './components/Stepper/index.js';
234
+ export type { StepperProps, StepperStep } from './components/Stepper/index.js';
235
+ export { ActionBar } from './components/ActionBar/index.js';
236
+ export type { ActionBarProps } from './components/ActionBar/index.js';
237
+ export { Sortable } from './components/Sortable/index.js';
238
+ export type { SortableProps } from './components/Sortable/index.js';
239
+ export { Kanban } from './components/Kanban/index.js';
240
+ export type { KanbanProps, KanbanColumn } from './components/Kanban/index.js';
231
241
  export type { OTPInputProps } from './components/OTPInput/index.js';
232
242
  export { DatePicker } from './components/DatePicker/index.js';
233
243
  export type { DatePickerProps } from './components/DatePicker/index.js';
package/dist/index.js CHANGED
@@ -128,6 +128,11 @@ import { TimePicker } from "./components/TimePicker/index.js";
128
128
  import { DateTimePicker } from "./components/DateTimePicker/index.js";
129
129
  import { EventCalendar } from "./components/EventCalendar/index.js";
130
130
  import { TreeView } from "./components/TreeView/index.js";
131
+ import { ResizablePanels } from "./components/ResizablePanels/index.js";
132
+ import { Stepper } from "./components/Stepper/index.js";
133
+ import { ActionBar } from "./components/ActionBar/index.js";
134
+ import { Sortable } from "./components/Sortable/index.js";
135
+ import { Kanban } from "./components/Kanban/index.js";
131
136
  import { DatePicker } from "./components/DatePicker/index.js";
132
137
  import { DateRangePicker } from "./components/DateRangePicker/index.js";
133
138
  import { todayIn } from "./components/DateRangePicker/index.js";
@@ -135,6 +140,7 @@ import { ThemeProvider, ThemeScript, useTheme } from "./components/ThemeProvider
135
140
  import { Fade, Slide, Scale, Collapse, ListTransition, SkeletonSwap, usePrefersReducedMotion, Reveal, Float, Marquee } from "./components/Motion/index.js";
136
141
  export {
137
142
  Accordion,
143
+ ActionBar,
138
144
  Alert,
139
145
  AlertDialog,
140
146
  Amount,
@@ -207,6 +213,7 @@ export {
207
213
  IconButton,
208
214
  InlineEdit,
209
215
  Input,
216
+ Kanban,
210
217
  Kbd,
211
218
  KeyboardShortcut,
212
219
  KpiTile,
@@ -239,6 +246,7 @@ export {
239
246
  RadioCardGroup,
240
247
  RadioGroup,
241
248
  Rating,
249
+ ResizablePanels,
242
250
  Reveal,
243
251
  SavedViews,
244
252
  Scale,
@@ -256,12 +264,14 @@ export {
256
264
  SkeletonSwap,
257
265
  Slide,
258
266
  Slider,
267
+ Sortable,
259
268
  SourceChip,
260
269
  SourceList,
261
270
  Sparkline,
262
271
  Spinner,
263
272
  SplitButton,
264
273
  Stack,
274
+ Stepper,
265
275
  StreamingText,
266
276
  Switch,
267
277
  Table,