@stll/ui 0.43.0 → 0.44.1

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.
@@ -13,8 +13,8 @@ import { VariantProps } from "class-variance-authority";
13
13
  */
14
14
  declare const buttonAccessibleDisabledClass = "cursor-not-allowed opacity-64";
15
15
  declare const buttonVariants: (props?: ({
16
- size?: "default" | "chip" | "icon" | "icon-lg" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "row" | "sm" | "xl" | "xs" | null | undefined;
17
- variant?: "link" | "destructive" | "muted" | "default" | "destructive-outline" | "destructive-ghost" | "ghost" | "outline" | "secondary" | null | undefined;
16
+ size?: "icon" | "sm" | "default" | "lg" | "row" | "chip" | "icon-lg" | "icon-sm" | "icon-xl" | "icon-xs" | "xl" | "xs" | null | undefined;
17
+ variant?: "link" | "destructive" | "muted" | "secondary" | "default" | "destructive-outline" | "destructive-ghost" | "ghost" | "outline" | null | undefined;
18
18
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
19
19
  type ButtonProps = {
20
20
  variant?: VariantProps<typeof buttonVariants>["variant"];
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- import { LoaderIcon } from "../icons.js";
3
2
  import { cn } from "../lib/utils.js";
4
3
  import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
5
4
  import { BUTTON_DISPOSITION, blockDisabledActivation, blockDisabledKeyActivation, resolveButtonDisposition } from "../lib/button-disposition.js";
6
5
  import { MENU_ROW_CLASS_NAME } from "../lib/menu-row.js";
6
+ import { Loader } from "./loader.js";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { mergeProps } from "@base-ui/react/merge-props";
9
9
  import { useRender } from "@base-ui/react/use-render";
@@ -62,16 +62,19 @@ function Button({ className, variant, size, render, loading, children, disabled,
62
62
  });
63
63
  const isAccessibleDisabled = disposition === BUTTON_DISPOSITION.accessibleDisabled;
64
64
  const defaultProps = {
65
- children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoaderIcon, {
66
- className: "animate-spin [transition:opacity_150ms_ease-out,scale_320ms_var(--ease-spring)] motion-reduce:transition-none starting:scale-50 starting:opacity-0",
67
- "data-slot": "button-loader"
65
+ children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Loader, {
66
+ className: "[transition:opacity_150ms_ease-out,scale_320ms_var(--ease-spring)] motion-reduce:transition-none starting:scale-50 starting:opacity-0",
67
+ "data-slot": "button-loader",
68
+ size: "sm",
69
+ variant: "decorative"
68
70
  }), children] }) : children,
69
71
  className: cn(buttonVariants({
70
72
  className,
71
73
  size,
72
74
  variant
73
- }), loading && "[&_svg:not([data-slot=button-loader])]:hidden", isAccessibleDisabled && "cursor-not-allowed opacity-64"),
75
+ }), loading && "[&_svg:not([data-slot=button-loader]_svg)]:hidden", isAccessibleDisabled && "cursor-not-allowed opacity-64"),
74
76
  "data-slot": "button",
77
+ "aria-busy": loading || void 0,
75
78
  ...isAccessibleDisabled ? {
76
79
  "aria-disabled": true,
77
80
  "data-disabled": "",
@@ -0,0 +1,10 @@
1
+ import { InlineDropPosition } from "../lib/inline-reorder.js";
2
+ //#region src/components/inline-drop-indicator.d.ts
3
+ /**
4
+ * The bar beside a dragged-over item in a horizontal row. Render it inside
5
+ * the item's positioned wrapper; `before`/`after` follow the text direction.
6
+ */
7
+ export declare const InlineDropIndicator: ({ position }: {
8
+ position: InlineDropPosition | null;
9
+ }) => import("react").JSX.Element | null;
10
+ //#endregion
@@ -0,0 +1,13 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/components/inline-drop-indicator.tsx
4
+ /**
5
+ * The bar beside a dragged-over item in a horizontal row. Render it inside
6
+ * the item's positioned wrapper; `before`/`after` follow the text direction.
7
+ */
8
+ const InlineDropIndicator = ({ position }) => position === null ? null : /* @__PURE__ */ jsx("span", {
9
+ "aria-hidden": "true",
10
+ className: cn("bg-primary pointer-events-none absolute inset-y-1 z-20 w-0.5 rounded-full", position === "before" ? "start-0" : "end-0")
11
+ });
12
+ //#endregion
13
+ export { InlineDropIndicator };
@@ -5,7 +5,7 @@ import { ComponentProps } from "react";
5
5
  * (`sm`) next to a control that is busy, `md` in a row, `lg` for a region.
6
6
  * Content with a known shape gets a `Skeleton` instead, never a loader.
7
7
  */
8
- declare const Loader: ({ label, size, className, ...props }: LoaderProps) => import("react").JSX.Element;
8
+ declare const Loader: ({ label, variant, size, className, ...props }: LoaderProps) => import("react").JSX.Element;
9
9
  /**
10
10
  * A region whose content has no shape yet (a job running, a first fetch): the
11
11
  * mark, one line saying what is happening, and at most one line of detail.
@@ -18,11 +18,17 @@ declare const LOADER_SIZE: {
18
18
  readonly lg: "size-8";
19
19
  };
20
20
  type LoaderSize = keyof typeof LOADER_SIZE;
21
- type LoaderProps = Omit<ComponentProps<"span">, "children"> & {
21
+ type LoaderProps = Omit<ComponentProps<"span">, "children" | "role" | "aria-label" | "aria-hidden" | "aria-busy"> & {
22
+ size?: LoaderSize;
23
+ } & ({
24
+ variant?: "status";
22
25
  /** What is pending, for assistive technology ("Loading matters"). */
23
26
  label: string;
24
- size?: LoaderSize;
25
- };
27
+ } | {
28
+ /** The surrounding control or text announces the pending state. */
29
+ variant: "decorative";
30
+ label?: never;
31
+ });
26
32
  type LoaderStateProps = {
27
33
  /** What is happening, shown as the title and announced. */
28
34
  label: string;
@@ -7,14 +7,15 @@ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  * (`sm`) next to a control that is busy, `md` in a row, `lg` for a region.
8
8
  * Content with a known shape gets a `Skeleton` instead, never a loader.
9
9
  */
10
- const Loader = ({ label, size = "md", className, ...props }) => /* @__PURE__ */ jsx("span", {
11
- "aria-busy": "true",
12
- "aria-label": label,
13
- className: cn("inline-flex shrink-0 items-center justify-center", className),
10
+ const Loader = ({ label, variant = "status", size = "md", className, ...props }) => /* @__PURE__ */ jsx("span", {
11
+ className: cn("inline-flex shrink-0 items-center justify-center", LOADER_SIZE[size], className),
14
12
  "data-slot": "loader",
15
- role: "status",
16
13
  ...props,
17
- children: /* @__PURE__ */ jsx(LoaderMark, { size })
14
+ "aria-busy": variant === "status" ? true : void 0,
15
+ "aria-hidden": variant === "decorative" ? true : void 0,
16
+ "aria-label": label,
17
+ role: variant === "status" ? "status" : void 0,
18
+ children: /* @__PURE__ */ jsx(LoaderMark, {})
18
19
  });
19
20
  /**
20
21
  * A region whose content has no shape yet (a job running, a first fetch): the
@@ -26,7 +27,10 @@ const LoaderState = ({ label, detail, hint, className }) => /* @__PURE__ */ jsxs
26
27
  className: cn("flex h-full flex-col items-center justify-center gap-3 px-6 text-center", className),
27
28
  "data-slot": "loader-state",
28
29
  role: "status",
29
- children: [/* @__PURE__ */ jsx(LoaderMark, { size: "lg" }), /* @__PURE__ */ jsxs("div", {
30
+ children: [/* @__PURE__ */ jsx("span", {
31
+ className: LOADER_SIZE.lg,
32
+ children: /* @__PURE__ */ jsx(LoaderMark, {})
33
+ }), /* @__PURE__ */ jsxs("div", {
30
34
  className: "space-y-1",
31
35
  children: [
32
36
  /* @__PURE__ */ jsx("p", {
@@ -49,6 +53,6 @@ const LOADER_SIZE = {
49
53
  md: "size-6",
50
54
  lg: "size-8"
51
55
  };
52
- const LoaderMark = ({ size }) => /* @__PURE__ */ jsx(StellaMark, { className: cn("animate-loader text-muted-foreground motion-reduce:animate-none motion-reduce:opacity-70", LOADER_SIZE[size]) });
56
+ const LoaderMark = () => /* @__PURE__ */ jsx(StellaMark, { className: "animate-loader text-muted-foreground size-full motion-reduce:animate-none motion-reduce:opacity-70" });
53
57
  //#endregion
54
58
  export { Loader, LoaderState };
@@ -33,7 +33,7 @@ declare function useSidebarLayout(): SidebarLayout;
33
33
  * left for the content column. Mobile reports 0: there the sidebar is an
34
34
  * overlay sheet and occupies no layout width.
35
35
  */
36
- declare function useSidebarInlineSize(): 0 | 256 | 48;
36
+ declare function useSidebarInlineSize(): 0 | 48 | 256;
37
37
  declare const SidebarProvider: ({ defaultOpen, forceCollapsed, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }: React.ComponentProps<"div"> & {
38
38
  defaultOpen?: boolean;
39
39
  forceCollapsed?: boolean;
@@ -86,7 +86,7 @@ declare const SidebarMenu: ({ className, ...props }: React.ComponentProps<"ul">)
86
86
  declare const SidebarMenuItem: ({ className, ...props }: React.ComponentProps<"li">) => import("react").JSX.Element;
87
87
  declare const sidebarMenuButtonVariants: (props?: ({
88
88
  variant?: "default" | "outline" | null | undefined;
89
- size?: "default" | "lg" | "sm" | "rail" | null | undefined;
89
+ size?: "rail" | "sm" | "default" | "lg" | null | undefined;
90
90
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
91
91
  /**
92
92
  * The footer's avatar trigger, signed in (user menu) or not (sign-in): a
@@ -6,12 +6,12 @@ type ToastData = {
6
6
  };
7
7
  declare const TOAST_RIGHT_OFFSET_VAR = "--stella-toast-right-offset";
8
8
  declare const TOAST_ICONS: {
9
- readonly error: React$1.ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & React$1.RefAttributes<SVGSVGElement>>;
10
- readonly info: React$1.ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & React$1.RefAttributes<SVGSVGElement>>;
11
- readonly loading: React$1.ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & React$1.RefAttributes<SVGSVGElement>>;
9
+ readonly error: React$1.JSX.Element;
10
+ readonly info: React$1.JSX.Element;
11
+ readonly loading: null;
12
12
  readonly neutral: null;
13
- readonly success: React$1.ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & React$1.RefAttributes<SVGSVGElement>>;
14
- readonly warning: React$1.ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & React$1.RefAttributes<SVGSVGElement>>;
13
+ readonly success: React$1.JSX.Element;
14
+ readonly warning: React$1.JSX.Element;
15
15
  };
16
16
  type ToastType = keyof typeof TOAST_ICONS;
17
17
  type ToastAction = {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
- import { CircleAlertIcon, CircleCheckIcon, InfoIcon, LoaderCircleIcon, TriangleAlertIcon, XIcon } from "../icons.js";
2
+ import { CircleAlertIcon, CircleCheckIcon, InfoIcon, TriangleAlertIcon, XIcon } from "../icons.js";
3
3
  import { cn } from "../lib/utils.js";
4
+ import { Loader } from "./loader.js";
4
5
  import { buttonVariants } from "./button.js";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import * as React$1 from "react";
@@ -10,12 +11,12 @@ const toastManager = Toast.createToastManager();
10
11
  const anchoredToastManager = Toast.createToastManager();
11
12
  const TOAST_RIGHT_OFFSET_VAR = "--stella-toast-right-offset";
12
13
  const TOAST_ICONS = {
13
- error: CircleAlertIcon,
14
- info: InfoIcon,
15
- loading: LoaderCircleIcon,
14
+ error: /* @__PURE__ */ jsx(CircleAlertIcon, { className: "text-destructive" }),
15
+ info: /* @__PURE__ */ jsx(InfoIcon, { className: "text-info" }),
16
+ loading: null,
16
17
  neutral: null,
17
- success: CircleCheckIcon,
18
- warning: TriangleAlertIcon
18
+ success: /* @__PURE__ */ jsx(CircleCheckIcon, { className: "text-success" }),
19
+ warning: /* @__PURE__ */ jsx(TriangleAlertIcon, { className: "text-warning" })
19
20
  };
20
21
  const stellaToast = Object.assign((title, options) => addToast(title, void 0, options), {
21
22
  add: (options) => toastManager.add(normalizeToastAddOptions(options)),
@@ -63,51 +64,44 @@ const Toasts = ({ position }) => {
63
64
  className: cn("fixed z-[90] mx-auto flex w-[calc(100%-var(--toast-inset)*2)] max-w-90 [--toast-inset:--spacing(4)] sm:[--toast-inset:--spacing(8)]", "md:data-[position*=right]:w-[calc(100%-var(--toast-inset)*2-min(var(--stella-toast-right-offset,0px),calc(100vw-var(--toast-inset)*2-10rem)))]", "data-[position*=top]:top-(--toast-inset)", "data-[position*=bottom]:bottom-(--toast-inset)", "data-[position*=left]:start-(--toast-inset)", "data-[position*=right]:end-(--toast-inset)", "md:data-[position*=right]:end-[calc(var(--toast-inset)+min(var(--stella-toast-right-offset,0px),calc(100vw-var(--toast-inset)*2-10rem)))]", "data-[position*=center]:left-1/2 data-[position*=center]:-translate-x-1/2"),
64
65
  "data-position": position,
65
66
  "data-slot": "toast-viewport",
66
- children: toasts.map((toastItem) => {
67
- const Icon = getToastIcon(toastItem.type);
68
- return /* @__PURE__ */ jsx(Toast.Root, {
69
- className: cn("bg-popover text-popover-foreground absolute z-[calc(9999-var(--toast-index))] h-(--toast-calc-height) w-full rounded-lg border shadow-lg/5 [transition:transform_.5s_var(--ease-smooth),opacity_.5s,height_.15s] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] motion-reduce:transition-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", "data-[position*=right]:start-auto data-[position*=right]:end-0", "data-[position*=left]:start-0 data-[position*=left]:end-auto", "data-[position*=center]:start-0 data-[position*=center]:end-0", "data-[position*=top]:top-0 data-[position*=top]:bottom-auto data-[position*=top]:origin-top", "data-[position*=bottom]:top-auto data-[position*=bottom]:bottom-0 data-[position*=bottom]:origin-bottom", "after:absolute after:start-0 after:h-[calc(var(--toast-gap)+1px)] after:w-full", "data-[position*=top]:after:top-full", "data-[position*=bottom]:after:bottom-full", "[--toast-calc-height:var(--toast-frontmost-height,var(--toast-height))] [--toast-gap:--spacing(3)] [--toast-peek:--spacing(3)] [--toast-scale:calc(max(0,1-(var(--toast-index)*.1)))] [--toast-shrink:calc(1-var(--toast-scale))]", "data-[position*=top]:[--toast-calc-offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--toast-gap)+var(--toast-swipe-movement-y))]", "data-[position*=bottom]:[--toast-calc-offset-y:calc(var(--toast-offset-y)*-1+var(--toast-index)*var(--toast-gap)*-1+var(--toast-swipe-movement-y))]", "data-[position*=top]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+(var(--toast-index)*var(--toast-peek))+(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]", "data-[position*=bottom]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--toast-peek))-(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]", "data-limited:opacity-0", "data-expanded:h-(--toast-height)", "data-position:data-expanded:transform-[translateX(var(--toast-swipe-movement-x))_translateY(var(--toast-calc-offset-y))]", "data-[position*=top]:data-starting-style:transform-[translateY(calc(-100%-var(--toast-inset)))]", "data-[position*=bottom]:data-starting-style:transform-[translateY(calc(100%+var(--toast-inset)))]", "data-ending-style:opacity-0", "data-ending-style:not-data-limited:not-data-swipe-direction:transform-[translateY(calc(100%+var(--toast-inset)))]", "data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]", "data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]", "data-expanded:data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-expanded:data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-expanded:data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]", "data-expanded:data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]"),
70
- "data-position": position,
71
- swipeDirection: (() => {
72
- if (position.includes("center")) return [isTop ? "up" : "down"];
73
- if (position.includes("left")) return ["left", isTop ? "up" : "down"];
74
- return ["right", isTop ? "up" : "down"];
75
- })(),
76
- toast: toastItem,
77
- children: /* @__PURE__ */ jsxs(Toast.Content, {
78
- className: "pointer-events-auto flex items-center gap-3 overflow-hidden px-3.5 py-3 text-sm transition-opacity duration-250 select-text data-behind:opacity-0 data-behind:not-data-expanded:pointer-events-none data-expanded:opacity-100",
79
- children: [/* @__PURE__ */ jsxs("div", {
80
- className: "flex min-w-0 flex-1 gap-2",
81
- children: [Icon && /* @__PURE__ */ jsx("div", {
82
- className: "select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&>svg]:h-lh [&>svg]:w-4",
83
- "data-slot": "toast-icon",
84
- children: /* @__PURE__ */ jsx(Icon, { className: "in-data-[type=error]:text-destructive in-data-[type=info]:text-info in-data-[type=success]:text-success in-data-[type=warning]:text-warning in-data-[type=loading]:animate-spin in-data-[type=loading]:opacity-80" })
85
- }), /* @__PURE__ */ jsxs("div", {
86
- className: "flex min-w-0 flex-col gap-0.5 select-text",
87
- children: [/* @__PURE__ */ jsx(Toast.Title, {
88
- className: "truncate font-medium",
89
- "data-slot": "toast-title"
90
- }), /* @__PURE__ */ jsx(Toast.Description, {
91
- className: "text-muted-foreground wrap-break-word",
92
- "data-slot": "toast-description"
93
- })]
94
- })]
95
- }), /* @__PURE__ */ jsxs("div", {
96
- className: "ms-auto flex shrink-0 items-center gap-2",
97
- children: [toastItem.actionProps && /* @__PURE__ */ jsx(Toast.Action, {
98
- className: cn(buttonVariants({ size: "xs" }), "select-none"),
99
- "data-slot": "toast-action",
100
- children: toastItem.actionProps.children
101
- }), /* @__PURE__ */ jsx(Toast.Close, {
102
- className: "text-muted-foreground hover:text-foreground shrink-0 cursor-pointer rounded p-0.5 select-none",
103
- "data-slot": "toast-close",
104
- "aria-label": "Close notification",
105
- children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
67
+ children: toasts.map((toastItem) => /* @__PURE__ */ jsx(Toast.Root, {
68
+ className: cn("bg-popover text-popover-foreground absolute z-[calc(9999-var(--toast-index))] h-(--toast-calc-height) w-full rounded-lg border shadow-lg/5 [transition:transform_.5s_var(--ease-smooth),opacity_.5s,height_.15s] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] motion-reduce:transition-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", "data-[position*=right]:start-auto data-[position*=right]:end-0", "data-[position*=left]:start-0 data-[position*=left]:end-auto", "data-[position*=center]:start-0 data-[position*=center]:end-0", "data-[position*=top]:top-0 data-[position*=top]:bottom-auto data-[position*=top]:origin-top", "data-[position*=bottom]:top-auto data-[position*=bottom]:bottom-0 data-[position*=bottom]:origin-bottom", "after:absolute after:start-0 after:h-[calc(var(--toast-gap)+1px)] after:w-full", "data-[position*=top]:after:top-full", "data-[position*=bottom]:after:bottom-full", "[--toast-calc-height:var(--toast-frontmost-height,var(--toast-height))] [--toast-gap:--spacing(3)] [--toast-peek:--spacing(3)] [--toast-scale:calc(max(0,1-(var(--toast-index)*.1)))] [--toast-shrink:calc(1-var(--toast-scale))]", "data-[position*=top]:[--toast-calc-offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--toast-gap)+var(--toast-swipe-movement-y))]", "data-[position*=bottom]:[--toast-calc-offset-y:calc(var(--toast-offset-y)*-1+var(--toast-index)*var(--toast-gap)*-1+var(--toast-swipe-movement-y))]", "data-[position*=top]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+(var(--toast-index)*var(--toast-peek))+(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]", "data-[position*=bottom]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--toast-peek))-(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]", "data-limited:opacity-0", "data-expanded:h-(--toast-height)", "data-position:data-expanded:transform-[translateX(var(--toast-swipe-movement-x))_translateY(var(--toast-calc-offset-y))]", "data-[position*=top]:data-starting-style:transform-[translateY(calc(-100%-var(--toast-inset)))]", "data-[position*=bottom]:data-starting-style:transform-[translateY(calc(100%+var(--toast-inset)))]", "data-ending-style:opacity-0", "data-ending-style:not-data-limited:not-data-swipe-direction:transform-[translateY(calc(100%+var(--toast-inset)))]", "data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]", "data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]", "data-expanded:data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-expanded:data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]", "data-expanded:data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]", "data-expanded:data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]"),
69
+ "data-position": position,
70
+ swipeDirection: (() => {
71
+ if (position.includes("center")) return [isTop ? "up" : "down"];
72
+ if (position.includes("left")) return ["left", isTop ? "up" : "down"];
73
+ return ["right", isTop ? "up" : "down"];
74
+ })(),
75
+ toast: toastItem,
76
+ children: /* @__PURE__ */ jsxs(Toast.Content, {
77
+ className: "pointer-events-auto flex items-center gap-3 overflow-hidden px-3.5 py-3 text-sm transition-opacity duration-250 select-text data-behind:opacity-0 data-behind:not-data-expanded:pointer-events-none data-expanded:opacity-100",
78
+ children: [/* @__PURE__ */ jsxs("div", {
79
+ className: "flex min-w-0 flex-1 gap-2",
80
+ children: [/* @__PURE__ */ jsx(ToastIcon, { type: toastItem.type }), /* @__PURE__ */ jsxs("div", {
81
+ className: "flex min-w-0 flex-col gap-0.5 select-text",
82
+ children: [/* @__PURE__ */ jsx(Toast.Title, {
83
+ className: "truncate font-medium",
84
+ "data-slot": "toast-title"
85
+ }), /* @__PURE__ */ jsx(Toast.Description, {
86
+ className: "text-muted-foreground wrap-break-word",
87
+ "data-slot": "toast-description"
106
88
  })]
107
89
  })]
108
- })
109
- }, toastItem.id);
110
- })
90
+ }), /* @__PURE__ */ jsxs("div", {
91
+ className: "ms-auto flex shrink-0 items-center gap-2",
92
+ children: [toastItem.actionProps && /* @__PURE__ */ jsx(Toast.Action, {
93
+ className: cn(buttonVariants({ size: "xs" }), "select-none"),
94
+ "data-slot": "toast-action",
95
+ children: toastItem.actionProps.children
96
+ }), /* @__PURE__ */ jsx(Toast.Close, {
97
+ className: "text-muted-foreground hover:text-foreground shrink-0 cursor-pointer rounded p-0.5 select-none",
98
+ "data-slot": "toast-close",
99
+ "aria-label": "Close notification",
100
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
101
+ })]
102
+ })]
103
+ })
104
+ }, toastItem.id))
111
105
  })
112
106
  });
113
107
  };
@@ -124,7 +118,6 @@ const AnchoredToasts = () => {
124
118
  className: "outline-none",
125
119
  "data-slot": "toast-viewport-anchored",
126
120
  children: toasts.map((toastItem) => {
127
- const Icon = getToastIcon(toastItem.type);
128
121
  const tooltipStyle = toastItem.data?.tooltipStyle ?? false;
129
122
  const positionerProps = toastItem.positionerProps;
130
123
  if (!positionerProps?.anchor) return null;
@@ -144,11 +137,7 @@ const AnchoredToasts = () => {
144
137
  className: "pointer-events-auto flex items-center gap-3 overflow-hidden px-3.5 py-3 text-sm select-text",
145
138
  children: [/* @__PURE__ */ jsxs("div", {
146
139
  className: "flex min-w-0 flex-1 gap-2",
147
- children: [Icon && /* @__PURE__ */ jsx("div", {
148
- className: "select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&>svg]:h-lh [&>svg]:w-4",
149
- "data-slot": "toast-icon",
150
- children: /* @__PURE__ */ jsx(Icon, { className: "in-data-[type=error]:text-destructive in-data-[type=info]:text-info in-data-[type=success]:text-success in-data-[type=warning]:text-warning in-data-[type=loading]:animate-spin in-data-[type=loading]:opacity-80" })
151
- }), /* @__PURE__ */ jsxs("div", {
140
+ children: [/* @__PURE__ */ jsx(ToastIcon, { type: toastItem.type }), /* @__PURE__ */ jsxs("div", {
152
141
  className: "flex min-w-0 flex-col gap-0.5 select-text",
153
142
  children: [/* @__PURE__ */ jsx(Toast.Title, {
154
143
  className: "truncate font-medium",
@@ -250,6 +239,21 @@ function isToastUpdateOptions(value) {
250
239
  if (Array.isArray(value) || React$1.isValidElement(value)) return false;
251
240
  return !(Symbol.iterator in value);
252
241
  }
242
+ const ToastIcon = ({ type }) => {
243
+ if (type === "loading") return /* @__PURE__ */ jsx(Loader, {
244
+ className: "h-lh w-4 opacity-80",
245
+ "data-slot": "toast-icon",
246
+ size: "sm",
247
+ variant: "decorative"
248
+ });
249
+ const icon = getToastIcon(type);
250
+ if (icon === null) return null;
251
+ return /* @__PURE__ */ jsx("div", {
252
+ className: "select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&>svg]:h-lh [&>svg]:w-4",
253
+ "data-slot": "toast-icon",
254
+ children: icon
255
+ });
256
+ };
253
257
  function getToastIcon(type) {
254
258
  if (!isToastType(type)) return null;
255
259
  return TOAST_ICONS[type];
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import { Tooltip, TooltipContent as TooltipPopup, TooltipCreateHandle, TooltipPr
7
7
  import { AlertDialog, AlertDialogBackdrop, AlertDialogClose, AlertDialogContent as AlertDialogPopup, AlertDialogCreateHandle, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPanel, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertDialogViewport } from "./components/alert-dialog.js";
8
8
  import { useIsMobile } from "./hooks/use-mobile.js";
9
9
  import { Inspector, InspectorActions, InspectorContent, InspectorDescription, InspectorEmptyRow, InspectorHeader, InspectorHeaderText, InspectorProperty, InspectorPropertyLabel, InspectorPropertyList, InspectorPropertyValue, InspectorRail, InspectorRailCell, InspectorRailContent, InspectorRailFooter, InspectorRailIconButton, InspectorRailTab, InspectorSection, InspectorSectionTitle, InspectorTitle } from "./inspector/chrome.js";
10
+ import { StellaMark } from "./components/stella-mark.js";
10
11
  import { Button, buttonAccessibleDisabledClass, buttonVariants } from "./components/button.js";
11
12
  import { ScrollArea, ScrollBar } from "./components/scroll-area.js";
12
13
  import { Sheet, SheetBackdrop, SheetClose, SheetContent as SheetPopup, SheetDescription, SheetFooter, SheetHeader, SheetPanel, SheetPortal, SheetTitle, SheetTrigger } from "./components/sheet.js";
@@ -62,7 +63,6 @@ import { SegmentedIconToggle } from "./components/segmented-icon-toggle.js";
62
63
  import { Separator, TextSeparator } from "./components/separator.js";
63
64
  import { Skeleton } from "./components/skeleton.js";
64
65
  import { SIDEBAR_WIDTH_ICON_PX, SIDEBAR_WIDTH_PX, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, sidebarIdentityTriggerClassName, useSidebar, useSidebarInlineSize, useSidebarLayout } from "./components/sidebar.js";
65
- import { StellaMark } from "./components/stella-mark.js";
66
66
  import { StellaWordmarkLatin } from "./components/stella-wordmark.js";
67
67
  import { SortableHead, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "./components/table.js";
68
68
  import { Tabs, TabsContent as TabsPanel, TabsList, TabsTab } from "./components/tabs.js";
@@ -1,4 +1,4 @@
1
- import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
1
+ import { draggable } from "@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter";
2
2
  //#region src/kanban/drag-interactions.d.ts
3
3
  type AtlaskitDraggableOptions = Parameters<typeof draggable>[0];
4
4
  /**
@@ -1,9 +1,9 @@
1
1
  import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
2
2
  import { autoScrollForExternal } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/external";
3
- import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
4
- import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
5
- import { centerUnderPointer } from "@atlaskit/pragmatic-drag-and-drop/element/center-under-pointer";
6
- import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
3
+ import { draggable } from "@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter";
4
+ import { centerUnderPointer } from "@atlaskit/pragmatic-drag-and-drop/utils/center-under-pointer";
5
+ import { combine } from "@atlaskit/pragmatic-drag-and-drop/utils/combine";
6
+ import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/utils/set-custom-native-drag-preview";
7
7
  //#region src/kanban/drag-interactions.ts
8
8
  /**
9
9
  * Marks a card drag on the native `DataTransfer` so the board's native
@@ -5,6 +5,6 @@ declare const CONTROL_SIZE: Readonly<{
5
5
  readonly lg: "lg";
6
6
  }>;
7
7
  type ControlSize = (typeof CONTROL_SIZE)[keyof typeof CONTROL_SIZE];
8
- declare const CONTROL_SIZES: readonly ("default" | "lg" | "sm")[];
8
+ declare const CONTROL_SIZES: readonly ("sm" | "default" | "lg")[];
9
9
  //#endregion
10
10
  export { CONTROL_SIZE, CONTROL_SIZES, type ControlSize };
@@ -0,0 +1,19 @@
1
+ //#region src/lib/inline-reorder.d.ts
2
+ /**
3
+ * Reordering for a horizontal row of items (tabs, chips) dragged with
4
+ * pragmatic drag and drop. Edges match the hitbox package's `Edge`, so a
5
+ * caller passes `extractClosestEdge(...)` straight through.
6
+ */
7
+ type InlineDropEdge = "top" | "right" | "bottom" | "left";
8
+ export type InlineDirection = "ltr" | "rtl";
9
+ export type InlineDropPosition = "before" | "after";
10
+ export declare const toInlineDropPosition: (edge: InlineDropEdge | null, direction: InlineDirection) => InlineDropPosition | null;
11
+ type ReorderInlineIdsParams = {
12
+ ids: readonly string[];
13
+ draggedId: string;
14
+ targetId: string;
15
+ position: InlineDropPosition;
16
+ };
17
+ /** The new order, or null when the drop leaves the order unchanged. */
18
+ export declare const reorderInlineIds: ({ ids, draggedId, targetId, position }: ReorderInlineIdsParams) => string[] | null;
19
+ //#endregion
@@ -0,0 +1,15 @@
1
+ //#region src/lib/inline-reorder.ts
2
+ const toInlineDropPosition = (edge, direction) => {
3
+ if (edge !== "left" && edge !== "right") return null;
4
+ return (direction === "rtl" ? edge === "left" : edge === "right") ? "after" : "before";
5
+ };
6
+ /** The new order, or null when the drop leaves the order unchanged. */
7
+ const reorderInlineIds = ({ ids, draggedId, targetId, position }) => {
8
+ if (draggedId === targetId || !ids.includes(draggedId) || !ids.includes(targetId)) return null;
9
+ const withoutDragged = ids.filter((id) => id !== draggedId);
10
+ const targetIndex = withoutDragged.indexOf(targetId);
11
+ const reordered = withoutDragged.toSpliced(position === "after" ? targetIndex + 1 : targetIndex, 0, draggedId);
12
+ return reordered.every((id, index) => id === ids[index]) ? null : reordered;
13
+ };
14
+ //#endregion
15
+ export { reorderInlineIds, toInlineDropPosition };
@@ -207,6 +207,15 @@
207
207
  }
208
208
 
209
209
  :root {
210
+ --chart-1: color-mix(in oklch, var(--option-blue) 70%, var(--foreground));
211
+ --chart-2: color-mix(in oklch, var(--option-emerald) 70%, var(--foreground));
212
+ --chart-3: color-mix(in oklch, var(--option-amber) 70%, var(--foreground));
213
+ --chart-4: color-mix(in oklch, var(--option-violet) 70%, var(--foreground));
214
+ --chart-5: color-mix(in oklch, var(--option-red) 70%, var(--foreground));
215
+ --chart-6: color-mix(in oklch, var(--option-cyan) 70%, var(--foreground));
216
+ --chart-7: color-mix(in oklch, var(--option-lime) 70%, var(--foreground));
217
+ --chart-8: color-mix(in oklch, var(--option-fuchsia) 70%, var(--foreground));
218
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
210
219
  --radius: 0.625rem;
211
220
  --background: var(--color-white);
212
221
  --foreground: var(--color-neutral-800);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/ui",
3
- "version": "0.43.0",
3
+ "version": "0.44.1",
4
4
  "description": "Stella's design system: bidi-aware React primitives built on Base UI, the dockable inspector pane, and the Tailwind v4 theme they are styled with.",
5
5
  "keywords": [
6
6
  "base-ui",
@@ -173,6 +173,14 @@
173
173
  "types": "./dist/components/inline-rename.d.ts",
174
174
  "import": "./dist/components/inline-rename.js"
175
175
  },
176
+ "./inline-reorder": {
177
+ "types": "./dist/lib/inline-reorder.d.ts",
178
+ "import": "./dist/lib/inline-reorder.js"
179
+ },
180
+ "./inline-drop-indicator": {
181
+ "types": "./dist/components/inline-drop-indicator.d.ts",
182
+ "import": "./dist/components/inline-drop-indicator.js"
183
+ },
176
184
  "./input-group": {
177
185
  "types": "./dist/components/input-group.d.ts",
178
186
  "import": "./dist/components/input-group.js"
@@ -666,8 +674,8 @@
666
674
  "temporal-polyfill": "1.0.5"
667
675
  },
668
676
  "devDependencies": {
669
- "@atlaskit/pragmatic-drag-and-drop": "^3.1.0",
670
- "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.2.0",
677
+ "@atlaskit/pragmatic-drag-and-drop": "^4.0.0",
678
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.2.1",
671
679
  "@base-ui/react": "1.8.0",
672
680
  "@playwright/test": "^1.63.0",
673
681
  "@stll/typescript-config": "0.0.0",
@@ -683,8 +691,8 @@
683
691
  "vite": "8.3.1"
684
692
  },
685
693
  "peerDependencies": {
686
- "@atlaskit/pragmatic-drag-and-drop": "^3.1.0",
687
- "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.2.0",
694
+ "@atlaskit/pragmatic-drag-and-drop": "^4.0.0",
695
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.2.1",
688
696
  "@base-ui/react": "^1.7.0",
689
697
  "@tanstack/react-virtual": "^3.14.13",
690
698
  "@types/react": ">=19",