@stll/ui 0.42.1 → 0.44.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/dist/components/button.d.ts +1 -1
- package/dist/components/button.js +8 -5
- package/dist/components/date-picker-popover.js +6 -1
- package/dist/components/details-grid.d.ts +10 -0
- package/dist/components/details-grid.js +26 -0
- package/dist/components/dialog-form-state.d.ts +16 -0
- package/dist/components/dialog-form-state.js +28 -0
- package/dist/components/dialog.d.ts +12 -2
- package/dist/components/dialog.js +89 -23
- package/dist/components/form.d.ts +4 -1
- package/dist/components/form.js +8 -3
- package/dist/components/inline-drop-indicator.d.ts +10 -0
- package/dist/components/inline-drop-indicator.js +13 -0
- package/dist/components/inline-rename.d.ts +12 -0
- package/dist/components/inline-rename.js +75 -0
- package/dist/components/input-group.d.ts +1 -1
- package/dist/components/loader.d.ts +10 -4
- package/dist/components/loader.js +12 -8
- package/dist/components/sidebar.d.ts +1 -1
- package/dist/components/split-button.d.ts +35 -0
- package/dist/components/split-button.js +64 -0
- package/dist/components/toast.d.ts +5 -5
- package/dist/components/toast.js +59 -55
- package/dist/components/toolbar-icon-action.d.ts +17 -0
- package/dist/components/toolbar-icon-action.js +23 -0
- package/dist/css.d.ts +3 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +6 -3
- package/dist/kanban/drag-interactions.d.ts +1 -1
- package/dist/kanban/drag-interactions.js +4 -4
- package/dist/lib/inline-reorder.d.ts +19 -0
- package/dist/lib/inline-reorder.js +15 -0
- package/dist/styles/inline-rename.css +69 -0
- package/dist/styles/theme.css +2 -0
- package/package.json +30 -6
|
@@ -14,7 +14,7 @@ import { VariantProps } from "class-variance-authority";
|
|
|
14
14
|
declare const buttonAccessibleDisabledClass = "cursor-not-allowed opacity-64";
|
|
15
15
|
declare const buttonVariants: (props?: ({
|
|
16
16
|
size?: "default" | "row" | "chip" | "icon" | "icon-lg" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "sm" | "xl" | "xs" | null | undefined;
|
|
17
|
-
variant?: "link" | "
|
|
17
|
+
variant?: "link" | "default" | "destructive" | "destructive-outline" | "destructive-ghost" | "ghost" | "muted" | "outline" | "secondary" | 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(
|
|
66
|
-
className: "
|
|
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": "",
|
|
@@ -427,6 +427,10 @@ const DatePickerPopoverContent = (props) => {
|
|
|
427
427
|
const selectedMonth = value ? Temporal.PlainDate.from(value).month - 1 : null;
|
|
428
428
|
const handleOpenChange = (open) => {
|
|
429
429
|
onOpenChange?.(open);
|
|
430
|
+
if (open) {
|
|
431
|
+
setViewMonthOverride(null);
|
|
432
|
+
setFocusedDate(value || today);
|
|
433
|
+
}
|
|
430
434
|
if (!open) {
|
|
431
435
|
setView("days");
|
|
432
436
|
setDecadeBaseOverride(decadeStart(viewYear));
|
|
@@ -452,7 +456,7 @@ const DatePickerPopoverContent = (props) => {
|
|
|
452
456
|
children: [
|
|
453
457
|
showIcon && /* @__PURE__ */ jsx(CalendarIcon, { className: "size-3.5 shrink-0" }),
|
|
454
458
|
/* @__PURE__ */ jsx("span", {
|
|
455
|
-
className: "min-w-0 flex-1
|
|
459
|
+
className: "min-w-0 flex-1 truncate text-start",
|
|
456
460
|
id: labelledBy ? displayValueId : void 0,
|
|
457
461
|
children: displayLabel
|
|
458
462
|
}),
|
|
@@ -462,6 +466,7 @@ const DatePickerPopoverContent = (props) => {
|
|
|
462
466
|
})
|
|
463
467
|
]
|
|
464
468
|
}), /* @__PURE__ */ jsx(PopoverPopup, {
|
|
469
|
+
initialFocus: () => gridRef.current?.querySelector(`[data-date="${value || today}"]`) ?? gridRef.current,
|
|
465
470
|
className: "data-starting-style:scale-100",
|
|
466
471
|
layer,
|
|
467
472
|
padding: "sm",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
//#region src/components/details-grid.d.ts
|
|
3
|
+
declare const DetailsGrid: ({ className, ...props }: React$1.ComponentProps<"dl">) => React$1.JSX.Element;
|
|
4
|
+
type DetailsItemProps = React$1.ComponentProps<"div"> & {
|
|
5
|
+
label: React$1.ReactNode;
|
|
6
|
+
span?: "wide";
|
|
7
|
+
};
|
|
8
|
+
declare const DetailsItem: ({ label, children, span, className, ...props }: DetailsItemProps) => React$1.JSX.Element;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { DetailsGrid, DetailsItem };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/details-grid.tsx
|
|
4
|
+
const DetailsGrid = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
5
|
+
className: "@container min-w-0",
|
|
6
|
+
"data-slot": "details-grid-container",
|
|
7
|
+
children: /* @__PURE__ */ jsx("dl", {
|
|
8
|
+
className: cn("grid grid-cols-[repeat(auto-fit,minmax(min(100%,20rem),1fr))] gap-x-6 gap-y-2 font-sans @min-[64rem]:grid-cols-3", className),
|
|
9
|
+
"data-slot": "details-grid",
|
|
10
|
+
...props
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
const DetailsItem = ({ label, children, span, className, ...props }) => /* @__PURE__ */ jsxs("div", {
|
|
14
|
+
className: cn("grid min-w-0 grid-cols-[minmax(0,7rem)_minmax(0,1fr)] items-start gap-x-4 text-xs", span === "wide" && "col-span-full", className),
|
|
15
|
+
"data-slot": "details-item",
|
|
16
|
+
...props,
|
|
17
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
18
|
+
className: "text-foreground-disabled min-w-0 font-medium tracking-wide wrap-anywhere uppercase",
|
|
19
|
+
children: label
|
|
20
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
21
|
+
className: "text-foreground-strong-muted min-w-0 wrap-anywhere",
|
|
22
|
+
children
|
|
23
|
+
})]
|
|
24
|
+
});
|
|
25
|
+
//#endregion
|
|
26
|
+
export { DetailsGrid, DetailsItem };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/components/dialog-form-state.d.ts
|
|
2
|
+
export type DialogFormSource = {
|
|
3
|
+
dirty: boolean;
|
|
4
|
+
onDiscard?: (() => void) | undefined;
|
|
5
|
+
};
|
|
6
|
+
export type DialogFormRegistry = {
|
|
7
|
+
sources: Map<string, DialogFormSource>;
|
|
8
|
+
clearConfirmation: () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const DialogFormContext: import("react").Context<DialogFormRegistry | null>;
|
|
11
|
+
/** Forms report semantic changes, including edits made by custom controls. */
|
|
12
|
+
export declare const DialogFormState: ({ dirty, onDiscard }: {
|
|
13
|
+
dirty: boolean;
|
|
14
|
+
onDiscard?: (() => void) | undefined;
|
|
15
|
+
}) => null;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext, useId, useLayoutEffect } from "react";
|
|
3
|
+
//#region src/components/dialog-form-state.tsx
|
|
4
|
+
const DialogFormContext = createContext(null);
|
|
5
|
+
/** Forms report semantic changes, including edits made by custom controls. */
|
|
6
|
+
const DialogFormState = ({ dirty, onDiscard }) => {
|
|
7
|
+
const registry = useContext(DialogFormContext);
|
|
8
|
+
const id = useId();
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
if (registry === null) return;
|
|
11
|
+
if (registry.sources.get(id)?.dirty !== dirty) registry.clearConfirmation();
|
|
12
|
+
registry.sources.set(id, {
|
|
13
|
+
dirty,
|
|
14
|
+
onDiscard
|
|
15
|
+
});
|
|
16
|
+
}, [
|
|
17
|
+
dirty,
|
|
18
|
+
id,
|
|
19
|
+
onDiscard,
|
|
20
|
+
registry
|
|
21
|
+
]);
|
|
22
|
+
useLayoutEffect(() => () => {
|
|
23
|
+
registry?.sources.delete(id);
|
|
24
|
+
}, [id, registry]);
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { DialogFormContext, DialogFormState };
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { OverlayLayer } from "../lib/overlay-layer.js";
|
|
2
|
+
import { DialogFormState } from "./dialog-form-state.js";
|
|
2
3
|
import * as React$1 from "react";
|
|
3
4
|
import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
|
|
4
5
|
//#region src/components/dialog.d.ts
|
|
5
6
|
declare const DialogCreateHandle: typeof Dialog$1.createHandle;
|
|
6
|
-
|
|
7
|
+
type DialogLabels = {
|
|
8
|
+
close: string;
|
|
9
|
+
unsavedChanges: string;
|
|
10
|
+
};
|
|
11
|
+
declare const DialogProvider: ({ labels, children }: React$1.PropsWithChildren<{
|
|
12
|
+
labels: DialogLabels;
|
|
13
|
+
}>) => React$1.JSX.Element;
|
|
14
|
+
declare const Dialog: <Payload>({ dirty, onOpenChange, onOpenChangeComplete, ...props }: Dialog$1.Root.Props<Payload> & {
|
|
15
|
+
dirty?: boolean;
|
|
16
|
+
}) => React$1.JSX.Element;
|
|
7
17
|
declare const DialogPortal: React$1.ForwardRefExoticComponent<Omit<import("@base-ui/react").AlertDialogPortalProps, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
8
18
|
declare function DialogTrigger({ tooltip, ...props }: Dialog$1.Trigger.Props & {
|
|
9
19
|
tooltip?: React$1.ReactNode;
|
|
@@ -34,4 +44,4 @@ declare const DialogPanel: ({ className, scrollFade, ...props }: React$1.Compone
|
|
|
34
44
|
scrollFade?: boolean;
|
|
35
45
|
}) => React$1.JSX.Element;
|
|
36
46
|
//#endregion
|
|
37
|
-
export { Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport };
|
|
47
|
+
export { Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogFormState, DialogHeader, DialogPanel, DialogPortal, DialogProvider, DialogTitle, DialogTrigger, DialogViewport };
|
|
@@ -5,11 +5,62 @@ import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
|
|
|
5
5
|
import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
|
|
6
6
|
import { Button } from "./button.js";
|
|
7
7
|
import { ScrollArea } from "./scroll-area.js";
|
|
8
|
+
import { DialogFormContext, DialogFormState } from "./dialog-form-state.js";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { createContext, useContext, useRef, useState } from "react";
|
|
9
11
|
import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
|
|
10
12
|
//#region src/components/dialog.tsx
|
|
11
13
|
const DialogCreateHandle = Dialog$1.createHandle;
|
|
12
|
-
const
|
|
14
|
+
const DialogLabelsContext = createContext({
|
|
15
|
+
close: "Close",
|
|
16
|
+
unsavedChanges: "Unsaved changes. Press Esc again to discard"
|
|
17
|
+
});
|
|
18
|
+
const DialogProvider = ({ labels, children }) => /* @__PURE__ */ jsx(DialogLabelsContext, {
|
|
19
|
+
value: labels,
|
|
20
|
+
children
|
|
21
|
+
});
|
|
22
|
+
const DialogDismissalContext = createContext("idle");
|
|
23
|
+
const Dialog = ({ dirty = false, onOpenChange, onOpenChangeComplete, ...props }) => {
|
|
24
|
+
const [dismissal, setDismissal] = useState("idle");
|
|
25
|
+
const pendingDiscard = useRef([]);
|
|
26
|
+
const [forms] = useState(() => ({
|
|
27
|
+
sources: /* @__PURE__ */ new Map(),
|
|
28
|
+
clearConfirmation: () => setDismissal("idle")
|
|
29
|
+
}));
|
|
30
|
+
return /* @__PURE__ */ jsx(DialogFormContext, {
|
|
31
|
+
value: forms,
|
|
32
|
+
children: /* @__PURE__ */ jsx(DialogDismissalContext, {
|
|
33
|
+
value: dismissal,
|
|
34
|
+
children: /* @__PURE__ */ jsx(Dialog$1.Root, {
|
|
35
|
+
...props,
|
|
36
|
+
onOpenChange: (open, details) => {
|
|
37
|
+
const hasChanges = dirty || [...forms.sources.values()].some((source) => source.dirty);
|
|
38
|
+
if (!open && details.reason === "escape-key" && hasChanges && (dismissal === "idle" || details.event.repeat)) {
|
|
39
|
+
details.cancel();
|
|
40
|
+
setDismissal("confirm-discard");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
onOpenChange?.(open, details);
|
|
44
|
+
if (details.isCanceled) return;
|
|
45
|
+
pendingDiscard.current = [];
|
|
46
|
+
if (!open) {
|
|
47
|
+
for (const source of forms.sources.values()) if (source.dirty && source.onDiscard !== void 0) pendingDiscard.current.push(source.onDiscard);
|
|
48
|
+
}
|
|
49
|
+
setDismissal("idle");
|
|
50
|
+
},
|
|
51
|
+
onOpenChangeComplete: (open) => {
|
|
52
|
+
if (!open) {
|
|
53
|
+
const callbacks = pendingDiscard.current;
|
|
54
|
+
pendingDiscard.current = [];
|
|
55
|
+
for (const discard of callbacks) discard();
|
|
56
|
+
setDismissal("idle");
|
|
57
|
+
}
|
|
58
|
+
onOpenChangeComplete?.(open);
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
};
|
|
13
64
|
const DialogPortal = Dialog$1.Portal;
|
|
14
65
|
function DialogTrigger({ tooltip, ...props }) {
|
|
15
66
|
return renderTooltipTrigger({
|
|
@@ -39,27 +90,42 @@ const DialogViewport = ({ className, layer = "default", ...props }) => /* @__PUR
|
|
|
39
90
|
"data-slot": "dialog-viewport",
|
|
40
91
|
...props
|
|
41
92
|
});
|
|
42
|
-
const DialogPopup = ({ backdropClassName, className, children, showCloseButton = true, bottomStickOnMobile = true, layer = "default", viewportClassName, ...props }) =>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
className: cn(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
93
|
+
const DialogPopup = ({ backdropClassName, className, children, showCloseButton = true, bottomStickOnMobile = true, layer = "default", viewportClassName, ...props }) => {
|
|
94
|
+
const dismissal = useContext(DialogDismissalContext);
|
|
95
|
+
const labels = useContext(DialogLabelsContext);
|
|
96
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, {
|
|
97
|
+
className: backdropClassName,
|
|
98
|
+
layer
|
|
99
|
+
}), /* @__PURE__ */ jsx(DialogViewport, {
|
|
100
|
+
className: cn(bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12", viewportClassName),
|
|
101
|
+
layer,
|
|
102
|
+
children: /* @__PURE__ */ jsxs(Dialog$1.Popup, {
|
|
103
|
+
className: cn("bg-popover text-popover-foreground relative row-start-2 flex max-h-full min-h-0 w-full max-w-lg min-w-0 -translate-y-[calc(1.25rem*var(--nested-dialogs))] scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-ending-style:opacity-0 data-nested:data-ending-style:translate-y-8 data-nested-dialog-open:origin-top data-starting-style:scale-98 data-starting-style:opacity-0 data-nested:data-starting-style:translate-y-8 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", bottomStickOnMobile && "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:before:hidden max-sm:before:rounded-none max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4", className),
|
|
104
|
+
"data-slot": "dialog-popup",
|
|
105
|
+
...props,
|
|
106
|
+
children: [
|
|
107
|
+
dismissal === "confirm-discard" && /* @__PURE__ */ jsx("div", {
|
|
108
|
+
className: "flex shrink-0 justify-end ps-2 pe-12 pt-2",
|
|
109
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
110
|
+
className: "text-muted-foreground max-w-64 px-2 py-1 text-xs",
|
|
111
|
+
role: "status",
|
|
112
|
+
children: labels.unsavedChanges
|
|
113
|
+
})
|
|
114
|
+
}),
|
|
115
|
+
children,
|
|
116
|
+
(showCloseButton || dismissal === "confirm-discard") && /* @__PURE__ */ jsx(Dialog$1.Close, {
|
|
117
|
+
"aria-label": labels.close,
|
|
118
|
+
className: "absolute end-2 top-2",
|
|
119
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
120
|
+
size: "icon",
|
|
121
|
+
variant: "ghost"
|
|
122
|
+
}),
|
|
123
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
})
|
|
127
|
+
})] });
|
|
128
|
+
};
|
|
63
129
|
const DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
64
130
|
className: cn("flex flex-col gap-2 p-6 in-[[data-slot=dialog-popup]:has([data-slot=dialog-panel])]:pb-3 max-sm:pb-4", className),
|
|
65
131
|
"data-slot": "dialog-header",
|
|
@@ -89,4 +155,4 @@ const DialogPanel = ({ className, scrollFade = true, ...props }) => /* @__PURE__
|
|
|
89
155
|
})
|
|
90
156
|
});
|
|
91
157
|
//#endregion
|
|
92
|
-
export { Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPortal, DialogTitle, DialogTrigger, DialogViewport };
|
|
158
|
+
export { Dialog, DialogBackdrop, DialogBackdrop as DialogOverlay, DialogClose, DialogPopup as DialogContent, DialogPopup, DialogCreateHandle, DialogDescription, DialogFooter, DialogFormState, DialogHeader, DialogPanel, DialogPortal, DialogProvider, DialogTitle, DialogTrigger, DialogViewport };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Form as Form$1 } from "@base-ui/react/form";
|
|
2
2
|
//#region src/components/form.d.ts
|
|
3
|
-
declare const Form: ({ className, ...props }: Form$1.Props
|
|
3
|
+
declare const Form: ({ className, dirty, onDiscard, children, ...props }: Form$1.Props & {
|
|
4
|
+
dirty?: boolean;
|
|
5
|
+
onDiscard?: (() => void) | undefined;
|
|
6
|
+
}) => import("react").JSX.Element;
|
|
4
7
|
//#endregion
|
|
5
8
|
export { Form };
|
package/dist/components/form.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { DialogFormState } from "./dialog-form-state.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { Form as Form$1 } from "@base-ui/react/form";
|
|
5
6
|
//#region src/components/form.tsx
|
|
6
|
-
const Form = ({ className, ...props }) => /* @__PURE__ */
|
|
7
|
+
const Form = ({ className, dirty = false, onDiscard, children, ...props }) => /* @__PURE__ */ jsxs(Form$1, {
|
|
7
8
|
className: cn("flex w-full flex-col gap-4", className),
|
|
8
9
|
"data-slot": "form",
|
|
9
|
-
...props
|
|
10
|
+
...props,
|
|
11
|
+
children: [/* @__PURE__ */ jsx(DialogFormState, {
|
|
12
|
+
dirty,
|
|
13
|
+
onDiscard
|
|
14
|
+
}), children]
|
|
10
15
|
});
|
|
11
16
|
//#endregion
|
|
12
17
|
export { Form };
|
|
@@ -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 };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
//#region src/components/inline-rename.d.ts
|
|
3
|
+
type InlineRenameInputProps = Omit<ComponentProps<"input">, "value" | "onChange" | "onKeyDown" | "size"> & {
|
|
4
|
+
value: string;
|
|
5
|
+
onValueChange: (value: string) => void;
|
|
6
|
+
onCommit: () => void;
|
|
7
|
+
onCancel: () => void;
|
|
8
|
+
/** Fill the parent's row instead of sizing to the text. */
|
|
9
|
+
fill?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const InlineRenameInput: ({ value, onValueChange, onCommit, onCancel, onBlur, className, ref, dir, fill, ...props }: InlineRenameInputProps) => import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { contentDir, isStructuredInputType } from "../hooks/use-content-dir.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useCallback, useImperativeHandle, useRef } from "react";
|
|
5
|
+
import { panic } from "better-result";
|
|
6
|
+
//#region src/components/inline-rename.tsx
|
|
7
|
+
/** Content-sized rename field; the title's parent owns its typography. */
|
|
8
|
+
const mirrorTextFor = (value, placeholder) => {
|
|
9
|
+
if (value !== "") return value;
|
|
10
|
+
if (placeholder !== void 0 && placeholder !== "") return placeholder;
|
|
11
|
+
return "";
|
|
12
|
+
};
|
|
13
|
+
const InlineRenameInput = ({ value, onValueChange, onCommit, onCancel, onBlur, className, ref, dir, fill = false, ...props }) => {
|
|
14
|
+
const finishedValue = useRef(null);
|
|
15
|
+
const inputRef = useRef(null);
|
|
16
|
+
useImperativeHandle(ref, () => {
|
|
17
|
+
if (!inputRef.current) panic("Inline rename input must be mounted before exposing its ref");
|
|
18
|
+
return inputRef.current;
|
|
19
|
+
}, []);
|
|
20
|
+
const focusInput = useCallback((input) => {
|
|
21
|
+
inputRef.current = input;
|
|
22
|
+
if (!input) return;
|
|
23
|
+
input.focus();
|
|
24
|
+
input.select();
|
|
25
|
+
}, []);
|
|
26
|
+
const mirrorText = mirrorTextFor(value, props.placeholder);
|
|
27
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
28
|
+
className: cn(className),
|
|
29
|
+
"data-fill": fill ? "" : void 0,
|
|
30
|
+
"data-slot": "inline-rename",
|
|
31
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
32
|
+
"aria-hidden": "true",
|
|
33
|
+
"data-slot": "inline-rename-mirror",
|
|
34
|
+
children: mirrorText
|
|
35
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
36
|
+
...props,
|
|
37
|
+
"data-slot": "inline-rename-input",
|
|
38
|
+
dir: dir ?? (isStructuredInputType(props.type) ? "ltr" : contentDir(value)),
|
|
39
|
+
size: void 0,
|
|
40
|
+
onBlur: (event) => {
|
|
41
|
+
if (finishedValue.current === value) {
|
|
42
|
+
event.stopPropagation();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (onBlur) {
|
|
46
|
+
onBlur(event);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
finishedValue.current = value;
|
|
50
|
+
onCommit();
|
|
51
|
+
},
|
|
52
|
+
onChange: (event) => {
|
|
53
|
+
finishedValue.current = null;
|
|
54
|
+
onValueChange(event.currentTarget.value);
|
|
55
|
+
},
|
|
56
|
+
onClick: (event) => event.stopPropagation(),
|
|
57
|
+
onKeyDown: (event) => {
|
|
58
|
+
event.stopPropagation();
|
|
59
|
+
if (event.nativeEvent.isComposing) return;
|
|
60
|
+
if (event.key !== "Enter" && event.key !== "Escape") return;
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
finishedValue.current = value;
|
|
63
|
+
if (event.key === "Escape") {
|
|
64
|
+
onCancel();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
onCommit();
|
|
68
|
+
},
|
|
69
|
+
ref: focusInput,
|
|
70
|
+
value
|
|
71
|
+
})]
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { InlineRenameInput };
|
|
@@ -5,7 +5,7 @@ import { VariantProps } from "class-variance-authority";
|
|
|
5
5
|
//#region src/components/input-group.d.ts
|
|
6
6
|
declare const InputGroup: ({ className, ...props }: React$1.ComponentProps<"div">) => React$1.JSX.Element;
|
|
7
7
|
declare const inputGroupAddonVariants: (props?: ({
|
|
8
|
-
align?: "inline-end" | "inline-start" | "block-
|
|
8
|
+
align?: "inline-end" | "inline-start" | "block-end" | "block-start" | null | undefined;
|
|
9
9
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
10
|
declare const InputGroupAddon: ({ className, align, ...props }: React$1.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) => React$1.JSX.Element;
|
|
11
11
|
declare const InputGroupText: ({ className, ...props }: React$1.ComponentProps<"span">) => React$1.JSX.Element;
|
|
@@ -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
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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(
|
|
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 = (
|
|
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 |
|
|
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;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Button } from "./button.js";
|
|
2
|
+
import { DropdownMenu as Menu } from "./menu.js";
|
|
3
|
+
import { Popover } from "./popover.js";
|
|
4
|
+
import { ComponentProps, ReactNode } from "react";
|
|
5
|
+
//#region src/components/split-button.d.ts
|
|
6
|
+
type SplitButtonSharedProps = {
|
|
7
|
+
menuLabel: string;
|
|
8
|
+
primaryDescriptionId?: string;
|
|
9
|
+
menuDescriptionId?: string;
|
|
10
|
+
onPrimaryClick: NonNullable<ComponentProps<typeof Button>["onClick"]>;
|
|
11
|
+
menu: ReactNode;
|
|
12
|
+
primaryDisabled?: boolean;
|
|
13
|
+
menuDisabled?: boolean;
|
|
14
|
+
size?: "sm" | "md";
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
type SplitButtonPrimary = {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
primaryLabel: string;
|
|
20
|
+
} | {
|
|
21
|
+
children: string;
|
|
22
|
+
primaryLabel?: never;
|
|
23
|
+
};
|
|
24
|
+
type SplitButtonProps = SplitButtonSharedProps & SplitButtonPrimary & ({
|
|
25
|
+
surface?: "menu";
|
|
26
|
+
open?: ComponentProps<typeof Menu>["open"];
|
|
27
|
+
onOpenChange?: ComponentProps<typeof Menu>["onOpenChange"];
|
|
28
|
+
} | {
|
|
29
|
+
surface: "popover";
|
|
30
|
+
open?: ComponentProps<typeof Popover>["open"];
|
|
31
|
+
onOpenChange?: ComponentProps<typeof Popover>["onOpenChange"];
|
|
32
|
+
});
|
|
33
|
+
/** Two independent actions share quiet chrome; only the chevron opens the secondary surface. */
|
|
34
|
+
export declare const SplitButton: (props: SplitButtonProps) => import("react").JSX.Element;
|
|
35
|
+
//#endregion
|