@nexub/react 7.3.0 → 7.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/Avatar/Avatar.d.ts +3 -0
- package/dist/components/Avatar/Avatar.js +28 -5
- package/dist/components/Avatar/index.d.ts +1 -1
- package/dist/components/Button/Button.d.ts +2 -1
- package/dist/components/Button/Button.js +37 -7
- package/dist/components/DataTable/DataTable.d.ts +5 -1
- package/dist/components/DataTable/DataTable.js +6 -2
- package/dist/components/Progress/Progress.d.ts +4 -0
- package/dist/components/Progress/Progress.js +73 -20
- package/dist/components/Skeleton/Skeleton.d.ts +9 -0
- package/dist/components/Skeleton/Skeleton.js +18 -1
- package/dist/components/Skeleton/index.d.ts +2 -2
- package/dist/components/Skeleton/index.js +2 -1
- package/dist/components/Toast/Toaster.js +68 -23
- package/dist/components/Toast/index.d.ts +1 -1
- package/dist/components/Toast/useToast.d.ts +18 -1
- package/dist/components/Toast/useToast.js +14 -0
- package/dist/hooks/useAsyncAction.d.ts +27 -0
- package/dist/hooks/useAsyncAction.js +36 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -6
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** `loading` shows a spinner and never auto-dismisses; update it (or use `toast.promise`) to settle it. */
|
|
3
|
+
export type ToastTone = 'success' | 'error' | 'warning' | 'info' | 'neutral' | 'loading';
|
|
2
4
|
export interface ToastItem {
|
|
3
5
|
id: string;
|
|
4
6
|
title: string;
|
|
5
7
|
description?: string;
|
|
6
8
|
tone?: ToastTone;
|
|
7
9
|
duration?: number;
|
|
10
|
+
/** Leading icon. Defaults to the tone's icon (none for neutral); `false` hides it. */
|
|
11
|
+
icon?: ReactNode | false;
|
|
12
|
+
/** A thin bar counting down the time left before auto-dismiss; pauses with the timer. */
|
|
13
|
+
showProgress?: boolean;
|
|
8
14
|
action?: {
|
|
9
15
|
label: string;
|
|
10
16
|
onClick: () => void;
|
|
@@ -31,6 +37,15 @@ export declare function useToastStore(): ToastItem[];
|
|
|
31
37
|
/** Runs a toast's onClose at most once. Internal: the Toaster calls it when Radix closes a toast. */
|
|
32
38
|
export declare function fireToastClose(item: ToastItem): void;
|
|
33
39
|
declare function dismiss(id?: string): void;
|
|
40
|
+
/** Changes an open toast in place (same element; a settled tone is announced once). No-op if it's gone. */
|
|
41
|
+
declare function update(id: string, patch: Partial<Omit<ToastItem, 'id'>>): void;
|
|
42
|
+
export interface PromiseToastOptions<T> {
|
|
43
|
+
loading: string;
|
|
44
|
+
success: string | ((value: T) => string);
|
|
45
|
+
error: string | ((error: unknown) => string);
|
|
46
|
+
}
|
|
47
|
+
/** Shows a loading toast, then turns that same toast into success or error. Returns `promise` as is. */
|
|
48
|
+
declare function promise<T>(promise: Promise<T>, { loading, success, error }: PromiseToastOptions<T>): Promise<T>;
|
|
34
49
|
declare function undoable(title: string, { onUndo, onCommit, undoLabel, description, duration }: UndoableToastOptions): string;
|
|
35
50
|
export declare const toast: {
|
|
36
51
|
success: (title: string, opts?: Partial<Omit<ToastItem, "id" | "title" | "tone">>) => string;
|
|
@@ -40,6 +55,8 @@ export declare const toast: {
|
|
|
40
55
|
custom: (title: string, opts?: Partial<Omit<ToastItem, "id" | "title" | "tone">>) => string;
|
|
41
56
|
/** A toast with an Undo action: Undo calls `onUndo`; any other close calls `onCommit`, once. */
|
|
42
57
|
undoable: typeof undoable;
|
|
58
|
+
update: typeof update;
|
|
59
|
+
promise: typeof promise;
|
|
43
60
|
dismiss: typeof dismiss;
|
|
44
61
|
};
|
|
45
62
|
export {};
|
|
@@ -41,6 +41,18 @@ function dismiss(id) {
|
|
|
41
41
|
closeFired.delete(item.id);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
function update(id, patch) {
|
|
45
|
+
g.__nexub_toast_items = g.__nexub_toast_items.map((i) => i.id === id ? { ...i, ...patch } : i);
|
|
46
|
+
notify();
|
|
47
|
+
}
|
|
48
|
+
function promise(promise2, { loading, success, error }) {
|
|
49
|
+
const id = add({ title: loading, tone: "loading" });
|
|
50
|
+
promise2.then(
|
|
51
|
+
(v) => update(id, { title: typeof success === "function" ? success(v) : success, tone: "success" }),
|
|
52
|
+
(e) => update(id, { title: typeof error === "function" ? error(e) : error, tone: "error" })
|
|
53
|
+
);
|
|
54
|
+
return promise2;
|
|
55
|
+
}
|
|
44
56
|
function undoable(title, { onUndo, onCommit, undoLabel, description, duration }) {
|
|
45
57
|
let undone = false;
|
|
46
58
|
return add({
|
|
@@ -65,6 +77,8 @@ const toast = {
|
|
|
65
77
|
custom: (title, opts) => add({ title, tone: "neutral", ...opts }),
|
|
66
78
|
/** A toast with an Undo action: Undo calls `onUndo`; any other close calls `onCommit`, once. */
|
|
67
79
|
undoable,
|
|
80
|
+
update,
|
|
81
|
+
promise,
|
|
68
82
|
dismiss
|
|
69
83
|
};
|
|
70
84
|
export {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AsyncAction<A extends unknown[], R> {
|
|
2
|
+
/** Calls `fn`. Resolves to its result, or `undefined` if it threw or a newer call (or `reset`) superseded it. Never rejects. */
|
|
3
|
+
run: (...args: A) => Promise<R | undefined>;
|
|
4
|
+
/** True while the latest call is in flight. */
|
|
5
|
+
pending: boolean;
|
|
6
|
+
/** What the latest call threw; cleared by the next `run` or `reset`. */
|
|
7
|
+
error: unknown;
|
|
8
|
+
/** Clears `pending` and `error` and ignores any call still in flight. */
|
|
9
|
+
reset: () => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Wraps an async function with pending/error state. The latest call wins:
|
|
13
|
+
* results and errors from older calls are dropped, and so is anything that
|
|
14
|
+
* settles after unmount.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const save = useAsyncAction(async (draft: Draft) => api.save(draft));
|
|
18
|
+
* <Button loading={save.pending} onClick={() => save.run(draft)}>Save</Button>
|
|
19
|
+
* {save.error ? <Alert tone="danger">Could not save</Alert> : null}
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* For optimistic UI, pair it with React 19 `useOptimistic`: apply the
|
|
23
|
+
* optimistic value inside `startTransition`, then `await run(...)`; React
|
|
24
|
+
* drops the optimistic value when the transition ends. Inside a
|
|
25
|
+
* `<form action>`, a `type="submit"` Button already tracks pending on its own.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useAsyncAction<A extends unknown[], R>(fn: (...args: A) => Promise<R> | R): AsyncAction<A, R>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
4
|
+
function useAsyncAction(fn) {
|
|
5
|
+
const [pending, setPending] = useState(false);
|
|
6
|
+
const [error, setError] = useState(void 0);
|
|
7
|
+
const latest = useRef(0);
|
|
8
|
+
const fnRef = useRef(fn);
|
|
9
|
+
useIsomorphicLayoutEffect(() => {
|
|
10
|
+
fnRef.current = fn;
|
|
11
|
+
});
|
|
12
|
+
useEffect(() => () => void latest.current++, []);
|
|
13
|
+
const run = useCallback(async (...args) => {
|
|
14
|
+
const id = ++latest.current;
|
|
15
|
+
setPending(true);
|
|
16
|
+
setError(void 0);
|
|
17
|
+
try {
|
|
18
|
+
const result = await fnRef.current(...args);
|
|
19
|
+
return id === latest.current ? result : void 0;
|
|
20
|
+
} catch (e) {
|
|
21
|
+
if (id === latest.current) setError(e);
|
|
22
|
+
return void 0;
|
|
23
|
+
} finally {
|
|
24
|
+
if (id === latest.current) setPending(false);
|
|
25
|
+
}
|
|
26
|
+
}, []);
|
|
27
|
+
const reset = useCallback(() => {
|
|
28
|
+
latest.current++;
|
|
29
|
+
setPending(false);
|
|
30
|
+
setError(void 0);
|
|
31
|
+
}, []);
|
|
32
|
+
return { run, pending, error, reset };
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
useAsyncAction
|
|
36
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export { useMediaQuery } from './hooks/useMediaQuery.js';
|
|
|
11
11
|
export { useMergedRefs } from './hooks/useMergedRefs.js';
|
|
12
12
|
export { useUnsavedChanges } from './hooks/useUnsavedChanges.js';
|
|
13
13
|
export { usePointerSheen } from './hooks/usePointerSheen.js';
|
|
14
|
+
export { useAsyncAction } from './hooks/useAsyncAction.js';
|
|
15
|
+
export type { AsyncAction } from './hooks/useAsyncAction.js';
|
|
14
16
|
export { PromptInput } from './components/PromptInput/index.js';
|
|
15
17
|
export type { PromptInputProps, PromptInputMessages, PromptInputStatus } from './components/PromptInput/index.js';
|
|
16
18
|
export { ThinkingIndicator } from './components/ThinkingIndicator/index.js';
|
|
@@ -84,7 +86,7 @@ export type { ChipProps } from './components/Chip/index.js';
|
|
|
84
86
|
export { EyebrowChip } from './components/EyebrowChip/index.js';
|
|
85
87
|
export type { EyebrowChipProps } from './components/EyebrowChip/index.js';
|
|
86
88
|
export { Avatar, avatarVariants } from './components/Avatar/index.js';
|
|
87
|
-
export type { AvatarProps } from './components/Avatar/index.js';
|
|
89
|
+
export type { AvatarProps, AvatarStatus } from './components/Avatar/index.js';
|
|
88
90
|
export { AvatarGroup, avatarGroupVariants } from './components/AvatarGroup/index.js';
|
|
89
91
|
export type { AvatarGroupProps } from './components/AvatarGroup/index.js';
|
|
90
92
|
export { Card, CardLink, cardVariants } from './components/Card/index.js';
|
|
@@ -97,8 +99,8 @@ export { MediaCard } from './components/MediaCard/index.js';
|
|
|
97
99
|
export type { MediaCardProps, MediaCardRatio } from './components/MediaCard/index.js';
|
|
98
100
|
export { Alert, alertVariants } from './components/Alert/index.js';
|
|
99
101
|
export type { AlertProps } from './components/Alert/index.js';
|
|
100
|
-
export { Skeleton, skeletonVariants } from './components/Skeleton/index.js';
|
|
101
|
-
export type { SkeletonProps } from './components/Skeleton/index.js';
|
|
102
|
+
export { Skeleton, SkeletonText, skeletonVariants } from './components/Skeleton/index.js';
|
|
103
|
+
export type { SkeletonProps, SkeletonTextProps } from './components/Skeleton/index.js';
|
|
102
104
|
export { Spinner, spinnerVariants } from './components/Spinner/index.js';
|
|
103
105
|
export type { SpinnerProps } from './components/Spinner/index.js';
|
|
104
106
|
export { Progress, progressTrackVariants, progressFillVariants } from './components/Progress/index.js';
|
|
@@ -256,3 +258,4 @@ export { Fade, Slide, Scale, Collapse, ListTransition, SkeletonSwap, usePrefersR
|
|
|
256
258
|
export type { FadeProps, SlideProps, SlideDirection, ScaleProps, CollapseProps, ListTransitionProps, SkeletonSwapProps, MotionDuration, MotionEasing, MotionBaseProps, RevealProps, FloatProps, MarqueeProps } from './components/Motion/index.js';
|
|
257
259
|
export type { DataTableColumn } from './components/DataTable/index.js';
|
|
258
260
|
export type { TableRootProps } from './components/Table/index.js';
|
|
261
|
+
export type { PromiseToastOptions } from './components/Toast/index.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { useMediaQuery } from "./hooks/useMediaQuery.js";
|
|
|
9
9
|
import { useMergedRefs } from "./hooks/useMergedRefs.js";
|
|
10
10
|
import { useUnsavedChanges } from "./hooks/useUnsavedChanges.js";
|
|
11
11
|
import { usePointerSheen } from "./hooks/usePointerSheen.js";
|
|
12
|
+
import { useAsyncAction } from "./hooks/useAsyncAction.js";
|
|
12
13
|
import { PromptInput } from "./components/PromptInput/index.js";
|
|
13
14
|
import { ThinkingIndicator } from "./components/ThinkingIndicator/index.js";
|
|
14
15
|
import { StreamingText } from "./components/StreamingText/index.js";
|
|
@@ -52,7 +53,7 @@ import { RadioCardGroup, RadioCard } from "./components/RadioCard/index.js";
|
|
|
52
53
|
import { CheckboxCard } from "./components/CheckboxCard/index.js";
|
|
53
54
|
import { MediaCard } from "./components/MediaCard/index.js";
|
|
54
55
|
import { Alert, alertVariants } from "./components/Alert/index.js";
|
|
55
|
-
import { Skeleton, skeletonVariants } from "./components/Skeleton/index.js";
|
|
56
|
+
import { Skeleton, SkeletonText, skeletonVariants } from "./components/Skeleton/index.js";
|
|
56
57
|
import { Spinner, spinnerVariants } from "./components/Spinner/index.js";
|
|
57
58
|
import { Progress, progressTrackVariants, progressFillVariants } from "./components/Progress/index.js";
|
|
58
59
|
import { Separator, separatorVariants } from "./components/Separator/index.js";
|
|
@@ -266,6 +267,7 @@ export {
|
|
|
266
267
|
Sidebar,
|
|
267
268
|
Skeleton,
|
|
268
269
|
SkeletonSwap,
|
|
270
|
+
SkeletonText,
|
|
269
271
|
Slide,
|
|
270
272
|
Slider,
|
|
271
273
|
Sortable,
|
|
@@ -342,6 +344,7 @@ export {
|
|
|
342
344
|
todayIn,
|
|
343
345
|
toggleVariants,
|
|
344
346
|
transitionName,
|
|
347
|
+
useAsyncAction,
|
|
345
348
|
useControllableState,
|
|
346
349
|
useDisclosure,
|
|
347
350
|
useForm,
|