@nexub/react 7.2.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.
Files changed (34) hide show
  1. package/accessibility.json +1 -1
  2. package/dist/components/Accordion/Accordion.js +1 -1
  3. package/dist/components/Avatar/Avatar.d.ts +3 -0
  4. package/dist/components/Avatar/Avatar.js +28 -5
  5. package/dist/components/Avatar/index.d.ts +1 -1
  6. package/dist/components/Button/Button.d.ts +2 -1
  7. package/dist/components/Button/Button.js +37 -7
  8. package/dist/components/DataTable/DataTable.d.ts +5 -1
  9. package/dist/components/DataTable/DataTable.js +6 -2
  10. package/dist/components/Motion/Collapse.d.ts +5 -4
  11. package/dist/components/Motion/Collapse.js +23 -53
  12. package/dist/components/Motion/motion.types.d.ts +2 -0
  13. package/dist/components/NavigationMenu/NavigationMenu.js +3 -1
  14. package/dist/components/Progress/Progress.d.ts +4 -0
  15. package/dist/components/Progress/Progress.js +74 -21
  16. package/dist/components/Skeleton/Skeleton.d.ts +9 -0
  17. package/dist/components/Skeleton/Skeleton.js +18 -1
  18. package/dist/components/Skeleton/index.d.ts +2 -2
  19. package/dist/components/Skeleton/index.js +2 -1
  20. package/dist/components/Tabs/Tabs.js +13 -3
  21. package/dist/components/Toast/Toaster.js +68 -23
  22. package/dist/components/Toast/index.d.ts +1 -1
  23. package/dist/components/Toast/useToast.d.ts +18 -1
  24. package/dist/components/Toast/useToast.js +14 -0
  25. package/dist/hooks/useAsyncAction.d.ts +27 -0
  26. package/dist/hooks/useAsyncAction.js +36 -0
  27. package/dist/hooks/useSlidingIndicator.d.ts +1 -1
  28. package/dist/hooks/useSlidingIndicator.js +2 -0
  29. package/dist/index.d.ts +6 -3
  30. package/dist/index.js +4 -1
  31. package/dist/styles.css +1 -1
  32. package/dist/utils/viewTransition.d.ts +4 -2
  33. package/dist/utils/viewTransition.js +10 -2
  34. package/package.json +6 -6
@@ -6,7 +6,7 @@ import { cn } from "../../utils/cn.js";
6
6
  import { useMergedRefs } from "../../hooks/useMergedRefs.js";
7
7
  import { useSlidingIndicator } from "../../hooks/useSlidingIndicator.js";
8
8
  const Root = React.forwardRef(
9
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadixTabs.Root, { ref, className: cn("flex flex-col gap-3", className), ...props })
9
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadixTabs.Root, { ref, className: cn("flex flex-col gap-3 data-[orientation=vertical]:flex-row", className), ...props })
10
10
  );
11
11
  Root.displayName = "Tabs.Root";
12
12
  const List = React.forwardRef(
@@ -18,8 +18,12 @@ const List = React.forwardRef(
18
18
  {
19
19
  ref: useMergedRefs(ref, forwardedRef),
20
20
  className: cn(
21
- "relative flex w-full items-stretch justify-start overflow-x-auto",
21
+ "group/tabs relative flex w-full items-stretch justify-start overflow-x-auto",
22
22
  "border-b border-[var(--color-outline-variant)]",
23
+ // Vertical: a column with the rule on the inline-end side.
24
+ "data-[orientation=vertical]:w-auto data-[orientation=vertical]:shrink-0 data-[orientation=vertical]:flex-col",
25
+ "data-[orientation=vertical]:overflow-x-visible data-[orientation=vertical]:overflow-y-auto",
26
+ "data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-e",
23
27
  className
24
28
  ),
25
29
  ...props,
@@ -32,7 +36,10 @@ const List = React.forwardRef(
32
36
  className: cn(
33
37
  "pointer-events-none absolute bottom-0 left-0 h-[3px] rounded-t-full bg-[var(--color-primary)]",
34
38
  "w-[var(--nx-ind-w,0px)] translate-x-[var(--nx-ind-x,0px)] opacity-[var(--nx-ind-o,0)]",
35
- "[[data-nx-indicator=ready]>&]:transition-[transform,width] [[data-nx-indicator=ready]>&]:duration-spatial-default [[data-nx-indicator=ready]>&]:ease-spatial-default"
39
+ "group-data-[orientation=vertical]/tabs:top-0 group-data-[orientation=vertical]/tabs:bottom-auto group-data-[orientation=vertical]/tabs:left-auto group-data-[orientation=vertical]/tabs:end-0",
40
+ "group-data-[orientation=vertical]/tabs:h-[var(--nx-ind-h,0px)] group-data-[orientation=vertical]/tabs:w-[3px] group-data-[orientation=vertical]/tabs:rounded-none group-data-[orientation=vertical]/tabs:rounded-s-full",
41
+ "group-data-[orientation=vertical]/tabs:translate-x-0 group-data-[orientation=vertical]/tabs:translate-y-[var(--nx-ind-y,0px)]",
42
+ "[[data-nx-indicator=ready]>&]:transition-[transform,width,height] [[data-nx-indicator=ready]>&]:duration-spatial-default [[data-nx-indicator=ready]>&]:ease-spatial-default"
36
43
  )
37
44
  }
38
45
  )
@@ -52,6 +59,7 @@ const Trigger = React.forwardRef(
52
59
  "nx-state-layer relative inline-flex h-control-md items-center justify-center whitespace-nowrap rounded-t-[var(--shape-field)] px-4 text-label-lg select-none",
53
60
  "text-[var(--color-on-surface-variant)] transition-colors duration-effects-fast ease-effects-fast",
54
61
  "data-[state=active]:text-[var(--color-primary)]",
62
+ "group-data-[orientation=vertical]/tabs:justify-start group-data-[orientation=vertical]/tabs:rounded-none group-data-[orientation=vertical]/tabs:rounded-s-[var(--shape-field)]",
55
63
  "disabled:pointer-events-none disabled:text-[var(--color-text-disabled)]",
56
64
  className
57
65
  ),
@@ -66,6 +74,8 @@ const Content = React.forwardRef(
66
74
  {
67
75
  ref,
68
76
  className: cn(
77
+ // Crossfade in on the effects spring (@starting-style, @nexub/themes/base).
78
+ "nx-tab-panel",
69
79
  className,
70
80
  // Radix hides inactive panels with the `hidden` attribute, which any
71
81
  // display class (`flex`, `md:grid`…) overrides. !important always wins.
@@ -2,7 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as RadixToast from "@radix-ui/react-toast";
5
- import { X } from "@nexub/icons";
5
+ import { AlertTriangle, CheckCircle2, Info, Loader2, X, XCircle } from "@nexub/icons";
6
6
  import { cn } from "../../utils/cn.js";
7
7
  import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect.js";
8
8
  import { useLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
@@ -12,8 +12,17 @@ const toneMap = {
12
12
  error: "border-s-4 border-[var(--color-error)]",
13
13
  warning: "border-s-4 border-[var(--color-warning)]",
14
14
  info: "border-s-4 border-[var(--color-info)]",
15
- neutral: ""
15
+ neutral: "",
16
+ loading: ""
16
17
  };
18
+ const toneIcon = {
19
+ success: /* @__PURE__ */ jsx(CheckCircle2, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-success-container)]" }),
20
+ error: /* @__PURE__ */ jsx(XCircle, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-error-container)]" }),
21
+ warning: /* @__PURE__ */ jsx(AlertTriangle, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-warning-container)]" }),
22
+ info: /* @__PURE__ */ jsx(Info, { size: "sm", "aria-hidden": "true", className: "shrink-0 text-[var(--color-info-container)]" }),
23
+ loading: /* @__PURE__ */ jsx(Loader2, { size: "sm", "aria-hidden": "true", className: "shrink-0 animate-spin motion-reduce:animate-none" })
24
+ };
25
+ const FLICK_VELOCITY = 0.11;
17
26
  const GAP = 8;
18
27
  const vertical = {
19
28
  top: { viewport: "top-0", toast: "top-4 origin-bottom", enter: "[--nx-y:calc(-100%-1rem)]" },
@@ -41,6 +50,8 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
41
50
  const state = React.useRef({ order, expanded, visibleToasts });
42
51
  state.current = { order, expanded, visibleToasts };
43
52
  const timers = React.useRef(/* @__PURE__ */ new Set());
53
+ const firstSeen = React.useRef(/* @__PURE__ */ new Map());
54
+ const swipeStart = React.useRef(0);
44
55
  React.useEffect(() => {
45
56
  const pending = timers.current;
46
57
  return () => pending.forEach(clearTimeout);
@@ -53,12 +64,12 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
53
64
  let front = 0;
54
65
  let stack = 0;
55
66
  order2.forEach((id, i) => {
56
- const el = ol.querySelector(`[data-toast-id="${id}"]`);
57
- if (!el) return;
58
- if (i === 0 || expanded2 || !heights.current.has(id)) heights.current.set(id, el.offsetHeight);
67
+ const el2 = ol.querySelector(`[data-toast-id="${id}"]`);
68
+ if (!el2) return;
69
+ if (i === 0 || expanded2 || !heights.current.has(id)) heights.current.set(id, el2.offsetHeight);
59
70
  const h2 = heights.current.get(id);
60
- el.style.setProperty("--nx-toast-index", String(i));
61
- el.style.setProperty("--nx-toast-offset", `${offset}px`);
71
+ el2.style.setProperty("--nx-toast-index", String(i));
72
+ el2.style.setProperty("--nx-toast-offset", `${offset}px`);
62
73
  if (i === 0) front = h2;
63
74
  if (i < visibleToasts2) stack = offset + h2;
64
75
  offset += h2 + GAP;
@@ -104,30 +115,53 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
104
115
  setFocused(false);
105
116
  }
106
117
  }, [order.length]);
118
+ const el = (id) => viewportRef.current?.querySelector(`[data-toast-id="${id}"]`);
119
+ const close = (t) => {
120
+ if (closed.has(t.id)) return;
121
+ fireToastClose(t);
122
+ setClosed((s) => new Set(s).add(t.id));
123
+ const timer = setTimeout(() => {
124
+ timers.current.delete(timer);
125
+ firstSeen.current.delete(t.id);
126
+ toast.dismiss(t.id);
127
+ setClosed((s) => {
128
+ const next = new Set(s);
129
+ next.delete(t.id);
130
+ return next;
131
+ });
132
+ }, 1e3);
133
+ timers.current.add(timer);
134
+ };
107
135
  return /* @__PURE__ */ jsxs(RadixToast.Provider, { swipeDirection: align === "start" === (dir === "rtl") ? "right" : "left", children: [
108
136
  toasts.map((t) => {
109
137
  const i = order.indexOf(t.id);
110
138
  const action = t.action ?? (t.undo && { label: t.undo.label ?? messages.undo, onClick: t.undo.onUndo });
139
+ if (!firstSeen.current.has(t.id)) firstSeen.current.set(t.id, t);
140
+ const announce = firstSeen.current.get(t.id) !== t && t.tone !== "loading" ? [t.title, t.description].filter(Boolean).join(". ") : "";
141
+ const icon = t.icon === false ? null : t.icon ?? toneIcon[t.tone ?? "neutral"];
142
+ const duration = t.tone === "loading" ? Infinity : t.duration ?? 5e3;
111
143
  return /* @__PURE__ */ jsxs(
112
144
  RadixToast.Root,
113
145
  {
114
146
  "data-toast-id": t.id,
115
147
  "data-front": i === -1 ? void 0 : i === 0,
116
148
  "data-hidden": i === -1 ? void 0 : i >= visibleToasts,
149
+ open: !closed.has(t.id),
117
150
  onOpenChange: (open) => {
118
- if (open) return;
119
- fireToastClose(t);
120
- setClosed((s) => new Set(s).add(t.id));
121
- const timer = setTimeout(() => {
122
- timers.current.delete(timer);
123
- toast.dismiss(t.id);
124
- setClosed((s) => {
125
- const next = new Set(s);
126
- next.delete(t.id);
127
- return next;
128
- });
129
- }, 1e3);
130
- timers.current.add(timer);
151
+ if (!open) close(t);
152
+ },
153
+ onPause: () => el(t.id)?.setAttribute("data-paused", ""),
154
+ onResume: () => el(t.id)?.removeAttribute("data-paused"),
155
+ onSwipeStart: () => {
156
+ swipeStart.current = performance.now();
157
+ },
158
+ onSwipeCancel: (e) => {
159
+ const { x, y } = e.detail.delta;
160
+ if (Math.hypot(x, y) / Math.max(1, performance.now() - swipeStart.current) < FLICK_VELOCITY) return;
161
+ e.preventDefault();
162
+ e.currentTarget.setAttribute("data-swipe", "end");
163
+ e.currentTarget.style.setProperty("--radix-toast-swipe-end-x", `${x}px`);
164
+ close(t);
131
165
  },
132
166
  className: cn(
133
167
  "group pointer-events-auto absolute inset-x-4 flex items-center justify-between gap-3 overflow-hidden rounded-shape-container bg-[var(--color-inverse-surface)] py-3 ps-4 pe-2 text-[var(--color-inverse-on-surface)] shadow-elevation-2",
@@ -152,9 +186,10 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
152
186
  align === "center" ? v.enter : h.enter,
153
187
  toneMap[t.tone ?? "neutral"]
154
188
  ),
155
- duration: t.duration ?? 5e3,
189
+ duration,
156
190
  children: [
157
- /* @__PURE__ */ jsxs("div", { className: "grid gap-1", children: [
191
+ icon,
192
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 gap-1", children: [
158
193
  /* @__PURE__ */ jsx(RadixToast.Title, { className: "text-title-sm", children: t.title }),
159
194
  t.description && /* @__PURE__ */ jsx(RadixToast.Description, { className: "text-body-sm text-[color-mix(in_srgb,var(--color-inverse-on-surface)_80%,transparent)]", children: t.description })
160
195
  ] }),
@@ -170,7 +205,17 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
170
205
  /* @__PURE__ */ jsxs(RadixToast.Close, { className: "nx-state-layer relative grid h-8 w-8 place-items-center rounded-full transition-opacity [@media(hover:hover)]:opacity-0 group-hover:opacity-100 focus-visible:opacity-100", children: [
171
206
  /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" }),
172
207
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: messages.close })
173
- ] })
208
+ ] }),
209
+ /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: announce }),
210
+ t.showProgress && duration !== Infinity && /* @__PURE__ */ jsx(
211
+ "span",
212
+ {
213
+ "aria-hidden": "true",
214
+ ref: (bar) => bar?.style.setProperty("animation-duration", `${duration}ms`),
215
+ className: "absolute inset-x-0 bottom-0 h-0.5 origin-left bg-current opacity-40 rtl:origin-right [animation:nx-scroll-progress_1s_linear_reverse_forwards] group-data-[paused]:[animation-play-state:paused] motion-reduce:hidden"
216
+ },
217
+ duration
218
+ )
174
219
  ]
175
220
  },
176
221
  t.id
@@ -2,4 +2,4 @@ export { Toast } from './Toast.js';
2
2
  export { Toaster } from './Toaster.js';
3
3
  export type { ToasterProps, ToasterPosition } from './Toaster.js';
4
4
  export { toast, useToastStore } from './useToast.js';
5
- export type { ToastItem, ToastTone, UndoableToastOptions } from './useToast.js';
5
+ export type { ToastItem, ToastTone, UndoableToastOptions, PromiseToastOptions } from './useToast.js';
@@ -1,10 +1,16 @@
1
- export type ToastTone = 'success' | 'error' | 'warning' | 'info' | 'neutral';
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
+ };
@@ -1,7 +1,7 @@
1
1
  import type * as React from 'react';
2
2
  /**
3
3
  * One indicator that slides to the active item (SegmentedControl thumb, Tabs
4
- * underline). Writes --nx-ind-x / -w / -o (opacity) on the (position: relative) root;
4
+ * underline). Writes --nx-ind-x / -w / -y / -h / -o (opacity) on the (position: relative) root;
5
5
  * CSS transitions do the motion. Sets data-nx-indicator="ready" one frame after
6
6
  * the first measure so the indicator doesn't animate in on mount.
7
7
  */
@@ -10,6 +10,8 @@ function useSlidingIndicator(ref, activeSelector) {
10
10
  if (!el) return;
11
11
  root.style.setProperty("--nx-ind-x", `${el.offsetLeft}px`);
12
12
  root.style.setProperty("--nx-ind-w", `${el.offsetWidth}px`);
13
+ root.style.setProperty("--nx-ind-y", `${el.offsetTop}px`);
14
+ root.style.setProperty("--nx-ind-h", `${el.offsetHeight}px`);
13
15
  };
14
16
  update();
15
17
  const frame = requestAnimationFrame(() => root.dataset.nxIndicator = "ready");
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,