@stll/ui 0.0.1-placeholder.0 → 0.3.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/README.md +84 -0
- package/dist/components/accordion.d.ts +8 -0
- package/dist/components/accordion.js +38 -0
- package/dist/components/alert-dialog.d.ts +32 -0
- package/dist/components/alert-dialog.js +75 -0
- package/dist/components/avatar.d.ts +7 -0
- package/dist/components/avatar.js +22 -0
- package/dist/components/bidi-text.d.ts +24 -0
- package/dist/components/bidi-text.js +38 -0
- package/dist/components/brand-icons.d.ts +7 -0
- package/dist/components/brand-icons.js +18 -0
- package/dist/components/breadcrumb.d.ts +12 -0
- package/dist/components/breadcrumb.js +61 -0
- package/dist/components/button-variants.d.ts +17 -0
- package/dist/components/button-variants.js +43 -0
- package/dist/components/button.d.ts +20 -0
- package/dist/components/button.js +53 -0
- package/dist/components/checkbox.d.ts +5 -0
- package/dist/components/checkbox.js +44 -0
- package/dist/components/color-picker.d.ts +47 -0
- package/dist/components/color-picker.js +249 -0
- package/dist/components/combobox.d.ts +40 -0
- package/dist/components/combobox.js +208 -0
- package/dist/components/command.d.ts +34 -0
- package/dist/components/command.js +100 -0
- package/dist/components/date-picker-popover.d.ts +29 -0
- package/dist/components/date-picker-popover.js +548 -0
- package/dist/components/date-picker-popover.logic.d.ts +14 -0
- package/dist/components/date-picker-popover.logic.js +26 -0
- package/dist/components/destructive-action-confirmation.d.ts +21 -0
- package/dist/components/destructive-action-confirmation.js +60 -0
- package/dist/components/destructive-confirm-dialog.d.ts +17 -0
- package/dist/components/destructive-confirm-dialog.js +49 -0
- package/dist/components/dialog.d.ts +37 -0
- package/dist/components/dialog.js +92 -0
- package/dist/components/directional-icon.d.ts +30 -0
- package/dist/components/directional-icon.js +12 -0
- package/dist/components/field.d.ts +11 -0
- package/dist/components/field.js +34 -0
- package/dist/components/form.d.ts +5 -0
- package/dist/components/form.js +12 -0
- package/dist/components/frame.d.ts +10 -0
- package/dist/components/frame.js +35 -0
- package/dist/components/hex-color-picker.d.ts +11 -0
- package/dist/components/hex-color-picker.js +366 -0
- package/dist/components/input-group.d.ts +15 -0
- package/dist/components/input-group.js +53 -0
- package/dist/components/input-otp.d.ts +13 -0
- package/dist/components/input-otp.js +39 -0
- package/dist/components/input.d.ts +12 -0
- package/dist/components/input.js +46 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.js +18 -0
- package/dist/components/menu.d.ts +44 -0
- package/dist/components/menu.js +152 -0
- package/dist/components/outline-rail.d.ts +43 -0
- package/dist/components/outline-rail.js +416 -0
- package/dist/components/pagination.d.ts +17 -0
- package/dist/components/pagination.js +78 -0
- package/dist/components/popover.d.ts +34 -0
- package/dist/components/popover.js +67 -0
- package/dist/components/preview-card.d.ts +12 -0
- package/dist/components/preview-card.js +25 -0
- package/dist/components/preview-pane.d.ts +23 -0
- package/dist/components/preview-pane.js +33 -0
- package/dist/components/scroll-area.d.ts +19 -0
- package/dist/components/scroll-area.js +38 -0
- package/dist/components/scroll-to-top.d.ts +12 -0
- package/dist/components/scroll-to-top.js +43 -0
- package/dist/components/secret-input.d.ts +9 -0
- package/dist/components/secret-input.js +38 -0
- package/dist/components/segmented-icon-toggle.d.ts +22 -0
- package/dist/components/segmented-icon-toggle.js +30 -0
- package/dist/components/select.d.ts +25 -0
- package/dist/components/select.js +196 -0
- package/dist/components/separator.d.ts +16 -0
- package/dist/components/separator.js +26 -0
- package/dist/components/sheet.d.ts +29 -0
- package/dist/components/sheet.js +87 -0
- package/dist/components/skeleton.d.ts +4 -0
- package/dist/components/skeleton.js +10 -0
- package/dist/components/stella-mark.d.ts +5 -0
- package/dist/components/stella-mark.js +12 -0
- package/dist/components/stella-wordmark.d.ts +5 -0
- package/dist/components/stella-wordmark.js +21 -0
- package/dist/components/table.d.ts +20 -0
- package/dist/components/table.js +80 -0
- package/dist/components/tabs.d.ts +11 -0
- package/dist/components/tabs.js +46 -0
- package/dist/components/textarea.d.ts +9 -0
- package/dist/components/textarea.js +31 -0
- package/dist/components/toast.d.ts +60 -0
- package/dist/components/toast.js +261 -0
- package/dist/components/tooltip-trigger-helper.d.ts +11 -0
- package/dist/components/tooltip-trigger-helper.js +14 -0
- package/dist/components/tooltip.d.ts +15 -0
- package/dist/components/tooltip.js +32 -0
- package/dist/data-table/index.d.ts +2 -0
- package/dist/data-table/index.js +2 -0
- package/dist/data-table/schema.d.ts +70 -0
- package/dist/data-table/schema.js +40 -0
- package/dist/hooks/use-contained-handler.d.ts +55 -0
- package/dist/hooks/use-contained-handler.js +54 -0
- package/dist/hooks/use-content-dir.d.ts +48 -0
- package/dist/hooks/use-content-dir.js +45 -0
- package/dist/hooks/use-mobile.d.ts +4 -0
- package/dist/hooks/use-mobile.js +16 -0
- package/dist/hooks/use-viewport-width.d.ts +5 -0
- package/dist/hooks/use-viewport-width.js +14 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +65 -0
- package/dist/inspector/chrome.d.ts +72 -0
- package/dist/inspector/chrome.js +153 -0
- package/dist/inspector/dock.d.ts +48 -0
- package/dist/inspector/dock.js +36 -0
- package/dist/inspector/index.d.ts +6 -0
- package/dist/inspector/index.js +6 -0
- package/dist/inspector/layout-tokens.d.ts +28 -0
- package/dist/inspector/layout-tokens.js +28 -0
- package/dist/inspector/pane-width.d.ts +64 -0
- package/dist/inspector/pane-width.js +53 -0
- package/dist/inspector/use-pane-width.d.ts +99 -0
- package/dist/inspector/use-pane-width.js +149 -0
- package/dist/kanban/card-properties.d.ts +27 -0
- package/dist/kanban/card-properties.js +19 -0
- package/dist/kanban/card-shell.d.ts +32 -0
- package/dist/kanban/card-shell.js +46 -0
- package/dist/kanban/column-header.d.ts +23 -0
- package/dist/kanban/column-header.js +24 -0
- package/dist/kanban/grouping.d.ts +84 -0
- package/dist/kanban/grouping.js +76 -0
- package/dist/kanban/index.d.ts +5 -0
- package/dist/kanban/index.js +5 -0
- package/dist/lib/button-disposition.d.ts +63 -0
- package/dist/lib/button-disposition.js +52 -0
- package/dist/lib/option-color.d.ts +28 -0
- package/dist/lib/option-color.js +59 -0
- package/dist/lib/overlay-layer.d.ts +22 -0
- package/dist/lib/overlay-layer.js +21 -0
- package/dist/lib/tab-order.d.ts +15 -0
- package/dist/lib/tab-order.js +15 -0
- package/dist/lib/tooltip-content.d.ts +13 -0
- package/dist/lib/tooltip-content.js +12 -0
- package/dist/lib/utils.d.ts +20 -0
- package/dist/lib/utils.js +41 -0
- package/dist/lib/week.d.ts +25 -0
- package/dist/lib/week.js +40 -0
- package/dist/styles/theme.css +1209 -0
- package/package.json +518 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { useContentDir } from "../hooks/use-content-dir.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
6
|
+
import { Field } from "@base-ui/react/field";
|
|
7
|
+
//#region src/components/textarea.tsx
|
|
8
|
+
const Textarea = ({ className, size = "default", unstyled = false, dir, onChange, ...props }) => {
|
|
9
|
+
const contentDir = useContentDir({
|
|
10
|
+
dir,
|
|
11
|
+
value: props.value,
|
|
12
|
+
defaultValue: props.defaultValue
|
|
13
|
+
});
|
|
14
|
+
const handleChange = (event) => {
|
|
15
|
+
contentDir.trackValue(event.currentTarget.value);
|
|
16
|
+
onChange?.(event);
|
|
17
|
+
};
|
|
18
|
+
return /* @__PURE__ */ jsx("span", {
|
|
19
|
+
className: cn(!unstyled && "border-input bg-background text-foreground ring-ring/24 has-focus-visible:border-ring has-aria-invalid:border-destructive/36 has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 relative inline-flex w-full rounded-lg border text-base shadow-xs/5 transition-shadow not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] has-focus-visible:ring-[3px] has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none sm:text-sm dark:not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]", className) || void 0,
|
|
20
|
+
"data-size": size,
|
|
21
|
+
"data-slot": "textarea-control",
|
|
22
|
+
children: /* @__PURE__ */ jsx(Field.Control, { render: (defaultProps) => /* @__PURE__ */ jsx("textarea", {
|
|
23
|
+
className: cn("field-sizing-content min-h-17.5 w-full rounded-[inherit] px-[calc(--spacing(3)-1px)] py-[calc(--spacing(1.5)-1px)] outline-none max-sm:min-h-20.5", size === "sm" && "min-h-16.5 px-[calc(--spacing(2.5)-1px)] py-[calc(--spacing(1)-1px)] max-sm:min-h-19.5", size === "lg" && "min-h-18.5 py-[calc(--spacing(2)-1px)] max-sm:min-h-21.5"),
|
|
24
|
+
"data-slot": "textarea",
|
|
25
|
+
...mergeProps(defaultProps, props, { onChange: handleChange }),
|
|
26
|
+
dir: contentDir.dir
|
|
27
|
+
}) })
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Textarea };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
import { Toast, ToastManagerAddOptions } from "@base-ui/react/toast";
|
|
3
|
+
//#region src/components/toast.d.ts
|
|
4
|
+
type ToastData = {
|
|
5
|
+
tooltipStyle?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const TOAST_RIGHT_OFFSET_VAR = "--stella-toast-right-offset";
|
|
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>>;
|
|
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>>;
|
|
15
|
+
};
|
|
16
|
+
type ToastType = keyof typeof TOAST_ICONS;
|
|
17
|
+
type ToastAction = {
|
|
18
|
+
label: React$1.ReactNode;
|
|
19
|
+
onClick?: React$1.MouseEventHandler<HTMLButtonElement>;
|
|
20
|
+
};
|
|
21
|
+
type ToastActionProps = ToastManagerAddOptions<ToastData>["actionProps"];
|
|
22
|
+
type ToastOptions = Omit<ToastManagerAddOptions<ToastData>, "actionProps" | "title" | "type"> & {
|
|
23
|
+
action?: ToastAction;
|
|
24
|
+
actionProps?: ToastActionProps;
|
|
25
|
+
};
|
|
26
|
+
type ToastUpdateOptions = Partial<ToastOptions> & {
|
|
27
|
+
title?: React$1.ReactNode | undefined;
|
|
28
|
+
type?: ToastType | undefined;
|
|
29
|
+
};
|
|
30
|
+
type ToastPromiseMessage = React$1.ReactNode | ToastUpdateOptions;
|
|
31
|
+
type ToastPromiseOptions<Value> = {
|
|
32
|
+
error: ToastPromiseMessage | ((error: unknown) => ToastPromiseMessage);
|
|
33
|
+
loading: ToastPromiseMessage;
|
|
34
|
+
success: ToastPromiseMessage | ((value: Value) => ToastPromiseMessage);
|
|
35
|
+
};
|
|
36
|
+
type ToastApi = {
|
|
37
|
+
(title: React$1.ReactNode, options?: ToastOptions): string;
|
|
38
|
+
add: (options: ToastAddOptions) => string;
|
|
39
|
+
close: (id?: string) => void;
|
|
40
|
+
dismiss: (id?: string) => void;
|
|
41
|
+
error: (title: React$1.ReactNode, options?: ToastOptions) => string;
|
|
42
|
+
info: (title: React$1.ReactNode, options?: ToastOptions) => string;
|
|
43
|
+
loading: (title: React$1.ReactNode, options?: ToastOptions) => string;
|
|
44
|
+
promise: <Value>(promiseValue: Promise<Value>, options: ToastPromiseOptions<Value>) => Promise<Value>;
|
|
45
|
+
success: (title: React$1.ReactNode, options?: ToastOptions) => string;
|
|
46
|
+
update: (id: string, options: ToastUpdateOptions) => void;
|
|
47
|
+
warning: (title: React$1.ReactNode, options?: ToastOptions) => string;
|
|
48
|
+
};
|
|
49
|
+
type ToastAddOptions = ToastUpdateOptions & {
|
|
50
|
+
title: React$1.ReactNode;
|
|
51
|
+
};
|
|
52
|
+
type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
|
|
53
|
+
type ToastProviderProps = {
|
|
54
|
+
position?: ToastPosition;
|
|
55
|
+
} & Toast.Provider.Props;
|
|
56
|
+
declare const stellaToast: ToastApi;
|
|
57
|
+
declare const ToastProvider: ({ children, position, ...props }: ToastProviderProps) => React$1.JSX.Element;
|
|
58
|
+
declare const AnchoredToastProvider: ({ children, ...props }: Toast.Provider.Props) => React$1.JSX.Element;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { AnchoredToastProvider, TOAST_RIGHT_OFFSET_VAR, type ToastPosition, ToastProvider, stellaToast };
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { buttonVariants } from "./button-variants.js";
|
|
4
|
+
import { CircleAlertIcon, CircleCheckIcon, InfoIcon, LoaderCircleIcon, TriangleAlertIcon, XIcon } from "lucide-react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import * as React$1 from "react";
|
|
7
|
+
import { Toast } from "@base-ui/react/toast";
|
|
8
|
+
//#region src/components/toast.tsx
|
|
9
|
+
const toastManager = Toast.createToastManager();
|
|
10
|
+
const anchoredToastManager = Toast.createToastManager();
|
|
11
|
+
const TOAST_RIGHT_OFFSET_VAR = "--stella-toast-right-offset";
|
|
12
|
+
const TOAST_ICONS = {
|
|
13
|
+
error: CircleAlertIcon,
|
|
14
|
+
info: InfoIcon,
|
|
15
|
+
loading: LoaderCircleIcon,
|
|
16
|
+
neutral: null,
|
|
17
|
+
success: CircleCheckIcon,
|
|
18
|
+
warning: TriangleAlertIcon
|
|
19
|
+
};
|
|
20
|
+
const stellaToast = Object.assign((title, options) => addToast(title, void 0, options), {
|
|
21
|
+
add: (options) => toastManager.add(normalizeToastAddOptions(options)),
|
|
22
|
+
close: (id) => {
|
|
23
|
+
toastManager.close(id);
|
|
24
|
+
},
|
|
25
|
+
dismiss: (id) => {
|
|
26
|
+
if (id === void 0) {
|
|
27
|
+
toastManager.close();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
toastManager.close(id);
|
|
31
|
+
},
|
|
32
|
+
error: (title, options) => addToast(title, "error", options),
|
|
33
|
+
info: (title, options) => addToast(title, "info", options),
|
|
34
|
+
loading: (title, options) => addToast(title, "loading", options),
|
|
35
|
+
promise: async (promiseValue, options) => {
|
|
36
|
+
const toastId = stellaToast.loading(getPromiseToastTitle(options.loading), getPromiseToastOptions(options.loading));
|
|
37
|
+
try {
|
|
38
|
+
const value = await promiseValue;
|
|
39
|
+
stellaToast.update(toastId, getPromiseToastUpdateOptions(options.success, value, "success"));
|
|
40
|
+
return value;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
stellaToast.update(toastId, getPromiseToastUpdateOptions(options.error, error, "error"));
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
success: (title, options) => addToast(title, "success", options),
|
|
47
|
+
update: (id, options) => {
|
|
48
|
+
toastManager.update(id, normalizeToastUpdateOptions(options));
|
|
49
|
+
},
|
|
50
|
+
warning: (title, options) => addToast(title, "warning", options)
|
|
51
|
+
});
|
|
52
|
+
const ToastProvider = ({ children, position = "bottom-right", ...props }) => /* @__PURE__ */ jsxs(Toast.Provider, {
|
|
53
|
+
toastManager,
|
|
54
|
+
...props,
|
|
55
|
+
children: [children, /* @__PURE__ */ jsx(Toasts, { position })]
|
|
56
|
+
});
|
|
57
|
+
const Toasts = ({ position }) => {
|
|
58
|
+
const { toasts } = Toast.useToastManager();
|
|
59
|
+
const isTop = position.startsWith("top");
|
|
60
|
+
return /* @__PURE__ */ jsx(Toast.Portal, {
|
|
61
|
+
"data-slot": "toast-portal",
|
|
62
|
+
children: /* @__PURE__ */ jsx(Toast.Viewport, {
|
|
63
|
+
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
|
+
"data-position": position,
|
|
65
|
+
"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_cubic-bezier(.22,1,.36,1),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%)] 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 break-words",
|
|
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 transition-colors select-none",
|
|
103
|
+
"data-slot": "toast-close",
|
|
104
|
+
"aria-label": "Close notification",
|
|
105
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
106
|
+
})]
|
|
107
|
+
})]
|
|
108
|
+
})
|
|
109
|
+
}, toastItem.id);
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const AnchoredToastProvider = ({ children, ...props }) => /* @__PURE__ */ jsxs(Toast.Provider, {
|
|
115
|
+
toastManager: anchoredToastManager,
|
|
116
|
+
...props,
|
|
117
|
+
children: [children, /* @__PURE__ */ jsx(AnchoredToasts, {})]
|
|
118
|
+
});
|
|
119
|
+
const AnchoredToasts = () => {
|
|
120
|
+
const { toasts } = Toast.useToastManager();
|
|
121
|
+
return /* @__PURE__ */ jsx(Toast.Portal, {
|
|
122
|
+
"data-slot": "toast-portal-anchored",
|
|
123
|
+
children: /* @__PURE__ */ jsx(Toast.Viewport, {
|
|
124
|
+
className: "outline-none",
|
|
125
|
+
"data-slot": "toast-viewport-anchored",
|
|
126
|
+
children: toasts.map((toastItem) => {
|
|
127
|
+
const Icon = getToastIcon(toastItem.type);
|
|
128
|
+
const tooltipStyle = toastItem.data?.tooltipStyle ?? false;
|
|
129
|
+
const positionerProps = toastItem.positionerProps;
|
|
130
|
+
if (!positionerProps?.anchor) return null;
|
|
131
|
+
return /* @__PURE__ */ jsx(Toast.Positioner, {
|
|
132
|
+
className: "z-50 max-w-[min(--spacing(64),var(--available-width))]",
|
|
133
|
+
"data-slot": "toast-positioner",
|
|
134
|
+
sideOffset: positionerProps.sideOffset ?? 4,
|
|
135
|
+
toast: toastItem,
|
|
136
|
+
children: /* @__PURE__ */ jsx(Toast.Root, {
|
|
137
|
+
className: cn("bg-popover text-popover-foreground relative border text-xs text-balance transition-[scale,opacity] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-ending-style:opacity-0 data-starting-style:scale-98 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", tooltipStyle ? "rounded-md shadow-md/5 before:rounded-[calc(var(--radius-md)-1px)]" : "rounded-lg shadow-lg/5 before:rounded-[calc(var(--radius-lg)-1px)]"),
|
|
138
|
+
"data-slot": "toast-popup",
|
|
139
|
+
toast: toastItem,
|
|
140
|
+
children: tooltipStyle ? /* @__PURE__ */ jsx(Toast.Content, {
|
|
141
|
+
className: "pointer-events-auto px-2 py-1 select-text",
|
|
142
|
+
children: /* @__PURE__ */ jsx(Toast.Title, { "data-slot": "toast-title" })
|
|
143
|
+
}) : /* @__PURE__ */ jsxs(Toast.Content, {
|
|
144
|
+
className: "pointer-events-auto flex items-center gap-3 overflow-hidden px-3.5 py-3 text-sm select-text",
|
|
145
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
146
|
+
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", {
|
|
152
|
+
className: "flex min-w-0 flex-col gap-0.5 select-text",
|
|
153
|
+
children: [/* @__PURE__ */ jsx(Toast.Title, {
|
|
154
|
+
className: "truncate font-medium",
|
|
155
|
+
"data-slot": "toast-title"
|
|
156
|
+
}), /* @__PURE__ */ jsx(Toast.Description, {
|
|
157
|
+
className: "text-muted-foreground break-words",
|
|
158
|
+
"data-slot": "toast-description"
|
|
159
|
+
})]
|
|
160
|
+
})]
|
|
161
|
+
}), toastItem.actionProps && /* @__PURE__ */ jsx(Toast.Action, {
|
|
162
|
+
className: cn(buttonVariants({ size: "xs" }), "ms-auto shrink-0 select-none"),
|
|
163
|
+
"data-slot": "toast-action",
|
|
164
|
+
children: toastItem.actionProps.children
|
|
165
|
+
})]
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}, toastItem.id);
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
function addToast(title, type, options) {
|
|
174
|
+
return toastManager.add(normalizeToastAddOptions({
|
|
175
|
+
...options,
|
|
176
|
+
title,
|
|
177
|
+
type
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
function normalizeToastAddOptions({ action, actionProps, timeout, type, ...options }) {
|
|
181
|
+
return {
|
|
182
|
+
...options,
|
|
183
|
+
...normalizeToastActionProps({
|
|
184
|
+
action,
|
|
185
|
+
actionProps
|
|
186
|
+
}),
|
|
187
|
+
timeout: normalizeToastTimeout(timeout ?? getDefaultToastTimeout(type)),
|
|
188
|
+
type
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function normalizeToastUpdateOptions(options) {
|
|
192
|
+
const { action, actionProps, timeout, type, ...updateOptions } = options;
|
|
193
|
+
const normalizedTimeout = timeout === void 0 ? normalizeDefaultToastUpdateTimeout(type) : normalizeToastTimeout(timeout);
|
|
194
|
+
return {
|
|
195
|
+
...updateOptions,
|
|
196
|
+
...normalizeToastActionProps({
|
|
197
|
+
action,
|
|
198
|
+
actionProps,
|
|
199
|
+
includeEmptyActionProps: Object.hasOwn(options, "action") || Object.hasOwn(options, "actionProps")
|
|
200
|
+
}),
|
|
201
|
+
...type === void 0 ? {} : { type },
|
|
202
|
+
...normalizedTimeout === void 0 ? {} : { timeout: normalizedTimeout }
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function normalizeDefaultToastUpdateTimeout(type) {
|
|
206
|
+
if (type === void 0) return;
|
|
207
|
+
return normalizeToastTimeout(getDefaultToastTimeout(type));
|
|
208
|
+
}
|
|
209
|
+
function normalizeToastActionProps({ action, actionProps, includeEmptyActionProps = false }) {
|
|
210
|
+
if (action === void 0) return actionProps === void 0 && !includeEmptyActionProps ? {} : { actionProps };
|
|
211
|
+
return { actionProps: {
|
|
212
|
+
...actionProps,
|
|
213
|
+
children: action.label,
|
|
214
|
+
onClick: action.onClick
|
|
215
|
+
} };
|
|
216
|
+
}
|
|
217
|
+
function getDefaultToastTimeout(type) {
|
|
218
|
+
if (type === "loading") return 0;
|
|
219
|
+
if (type === "error" || type === "warning") return 6e3;
|
|
220
|
+
return 4e3;
|
|
221
|
+
}
|
|
222
|
+
function normalizeToastTimeout(timeout) {
|
|
223
|
+
if (timeout === Number.POSITIVE_INFINITY) return 0;
|
|
224
|
+
return timeout;
|
|
225
|
+
}
|
|
226
|
+
function getPromiseToastTitle(option) {
|
|
227
|
+
return isToastUpdateOptions(option) ? option.title : option;
|
|
228
|
+
}
|
|
229
|
+
function getPromiseToastOptions(option) {
|
|
230
|
+
return isToastUpdateOptions(option) ? option : void 0;
|
|
231
|
+
}
|
|
232
|
+
function getPromiseToastUpdateOptions(option, value, type) {
|
|
233
|
+
const resolved = typeof option === "function" ? option(value) : option;
|
|
234
|
+
if (isToastUpdateOptions(resolved)) {
|
|
235
|
+
const hasReplacementAction = resolved.action !== void 0 || Object.hasOwn(resolved, "actionProps");
|
|
236
|
+
return {
|
|
237
|
+
...resolved,
|
|
238
|
+
...hasReplacementAction ? {} : { actionProps: void 0 },
|
|
239
|
+
type
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
actionProps: void 0,
|
|
244
|
+
title: resolved,
|
|
245
|
+
type
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function isToastUpdateOptions(value) {
|
|
249
|
+
if (typeof value !== "object" || value === null) return false;
|
|
250
|
+
if (Array.isArray(value) || React$1.isValidElement(value)) return false;
|
|
251
|
+
return !(Symbol.iterator in value);
|
|
252
|
+
}
|
|
253
|
+
function getToastIcon(type) {
|
|
254
|
+
if (!isToastType(type)) return null;
|
|
255
|
+
return TOAST_ICONS[type];
|
|
256
|
+
}
|
|
257
|
+
function isToastType(type) {
|
|
258
|
+
return typeof type === "string" && type in TOAST_ICONS;
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
export { AnchoredToastProvider, TOAST_RIGHT_OFFSET_VAR, ToastProvider, stellaToast };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OverlayLayer } from "../lib/overlay-layer.js";
|
|
2
|
+
import * as React$1 from "react";
|
|
3
|
+
//#region src/components/tooltip-trigger-helper.d.ts
|
|
4
|
+
type TooltipTriggerOptions = {
|
|
5
|
+
trigger: React$1.ReactElement;
|
|
6
|
+
tooltip: React$1.ReactNode;
|
|
7
|
+
layer?: OverlayLayer | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const renderTooltipTrigger: ({ trigger, tooltip, layer }: TooltipTriggerOptions) => React$1.JSX.Element;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { renderTooltipTrigger };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { hasTooltipContent } from "../lib/tooltip-content.js";
|
|
3
|
+
import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/tooltip-trigger-helper.tsx
|
|
6
|
+
const renderTooltipTrigger = ({ trigger, tooltip, layer }) => {
|
|
7
|
+
if (!hasTooltipContent(tooltip)) return trigger;
|
|
8
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: trigger }), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
9
|
+
...layer === void 0 ? {} : { layer },
|
|
10
|
+
children: tooltip
|
|
11
|
+
})] });
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { renderTooltipTrigger };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { OverlayLayer } from "../lib/overlay-layer.js";
|
|
2
|
+
import { Tooltip as Tooltip$1 } from "@base-ui/react/tooltip";
|
|
3
|
+
//#region src/components/tooltip.d.ts
|
|
4
|
+
declare const TooltipCreateHandle: typeof Tooltip$1.createHandle;
|
|
5
|
+
declare const TooltipProvider: import("react").FC<import("@base-ui/react").TooltipProviderProps>;
|
|
6
|
+
declare const Tooltip: <Payload>(props: Tooltip$1.Root.Props<Payload>) => import("react").JSX.Element;
|
|
7
|
+
declare const TooltipTrigger: (props: Tooltip$1.Trigger.Props) => import("react").JSX.Element;
|
|
8
|
+
declare const TooltipPopup: ({ className, align, sideOffset, side, layer, children, ...props }: Tooltip$1.Popup.Props & {
|
|
9
|
+
align?: Tooltip$1.Positioner.Props["align"];
|
|
10
|
+
side?: Tooltip$1.Positioner.Props["side"];
|
|
11
|
+
sideOffset?: Tooltip$1.Positioner.Props["sideOffset"];
|
|
12
|
+
layer?: OverlayLayer;
|
|
13
|
+
}) => import("react").JSX.Element;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { Tooltip as Tooltip$1 } from "@base-ui/react/tooltip";
|
|
6
|
+
//#region src/components/tooltip.tsx
|
|
7
|
+
const TooltipCreateHandle = Tooltip$1.createHandle;
|
|
8
|
+
const TooltipProvider = Tooltip$1.Provider;
|
|
9
|
+
const Tooltip = Tooltip$1.Root;
|
|
10
|
+
const TooltipTrigger = (props) => /* @__PURE__ */ jsx(Tooltip$1.Trigger, {
|
|
11
|
+
"data-slot": "tooltip-trigger",
|
|
12
|
+
...props
|
|
13
|
+
});
|
|
14
|
+
const TooltipPopup = ({ className, align = "center", sideOffset = 4, side = "top", layer = "default", children, ...props }) => /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsx(Tooltip$1.Positioner, {
|
|
15
|
+
align,
|
|
16
|
+
className: cn("h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom,transform] data-instant:transition-none", OVERLAY_LAYER_CLASS_NAMES[layer]),
|
|
17
|
+
"data-slot": "tooltip-positioner",
|
|
18
|
+
side,
|
|
19
|
+
sideOffset,
|
|
20
|
+
children: /* @__PURE__ */ jsx(Tooltip$1.Popup, {
|
|
21
|
+
className: cn("bg-popover text-popover-foreground relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) rounded-md border text-xs text-balance shadow-md/5 transition-[width,height,scale,opacity] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-ending-style:opacity-0 data-instant:duration-0 data-starting-style:scale-98 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
|
|
22
|
+
"data-slot": "tooltip-popup",
|
|
23
|
+
...props,
|
|
24
|
+
children: /* @__PURE__ */ jsx(Tooltip$1.Viewport, {
|
|
25
|
+
className: "relative size-full overflow-clip px-(--viewport-inline-padding) py-1 [--viewport-inline-padding:--spacing(2)] **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-current:transition-opacity **:data-current:data-ending-style:opacity-0 data-instant:transition-none **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:truncate **:data-previous:opacity-100 **:data-previous:transition-opacity **:data-previous:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-starting-style:opacity-0",
|
|
26
|
+
"data-slot": "tooltip-viewport",
|
|
27
|
+
children
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
}) });
|
|
31
|
+
//#endregion
|
|
32
|
+
export { Tooltip, TooltipPopup as TooltipContent, TooltipPopup, TooltipCreateHandle, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { TableColumnCapabilities, TableColumnDescriptor, TableSchema, duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds } from "./schema.js";
|
|
2
|
+
export { type TableColumnCapabilities, type TableColumnDescriptor, type TableSchema, duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds } from "./schema.js";
|
|
2
|
+
export { duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/data-table/schema.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A table's schema: which columns exist, what each can do, and how wide it
|
|
4
|
+
* starts. Not how a cell draws — that is the caller's, and it is the reason
|
|
5
|
+
* this module holds no React.
|
|
6
|
+
*
|
|
7
|
+
* The split matters because "which columns does this view have, and which of
|
|
8
|
+
* them can be sorted, hidden, resized or pinned" is a question about data, and
|
|
9
|
+
* a question about data can be answered by a test. It used to be answerable
|
|
10
|
+
* only by rendering the table and asking TanStack.
|
|
11
|
+
*/
|
|
12
|
+
/** What a reader may do to a column. */
|
|
13
|
+
type TableColumnCapabilities = {
|
|
14
|
+
sort: boolean;
|
|
15
|
+
hide: boolean;
|
|
16
|
+
resize: boolean;
|
|
17
|
+
pin: boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* One column.
|
|
21
|
+
*
|
|
22
|
+
* `render` is whatever the caller needs to draw the column: this module never
|
|
23
|
+
* looks inside it, which is what keeps the schema free of any idea about what
|
|
24
|
+
* a row holds.
|
|
25
|
+
*/
|
|
26
|
+
type TableColumnDescriptor<TRender> = {
|
|
27
|
+
/** Unique within the schema, and stable across renders. */
|
|
28
|
+
id: string;
|
|
29
|
+
/** Header text. Empty for a column whose header draws no text. */
|
|
30
|
+
label: string;
|
|
31
|
+
render: TRender;
|
|
32
|
+
/** Starting width, in pixels. */
|
|
33
|
+
size: number;
|
|
34
|
+
/** Narrowest this column may be resized to; the schema's default if absent. */
|
|
35
|
+
minSize?: number | undefined;
|
|
36
|
+
capabilities: TableColumnCapabilities;
|
|
37
|
+
/**
|
|
38
|
+
* Metadata columns read quieter than content ones; a utility column
|
|
39
|
+
* (a selection checkbox, an add-column affordance) draws no value at all.
|
|
40
|
+
*/
|
|
41
|
+
emphasis: "content" | "metadata" | "utility";
|
|
42
|
+
};
|
|
43
|
+
type TableSchema<TRender> = {
|
|
44
|
+
columns: readonly TableColumnDescriptor<TRender>[];
|
|
45
|
+
/** Narrowest any column may be resized to. */
|
|
46
|
+
defaultMinSize: number;
|
|
47
|
+
};
|
|
48
|
+
/** Every column a schema declares, in order. */
|
|
49
|
+
declare const tableColumnIds: <TRender>(schema: TableSchema<TRender>) => string[];
|
|
50
|
+
declare const sortableColumnIds: <TRender>(schema: TableSchema<TRender>) => string[];
|
|
51
|
+
declare const hideableColumnIds: <TRender>(schema: TableSchema<TRender>) => string[];
|
|
52
|
+
declare const findTableColumn: <TRender>(schema: TableSchema<TRender>, id: string) => TableColumnDescriptor<TRender> | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Which columns a view shows.
|
|
55
|
+
*
|
|
56
|
+
* A column that cannot be hidden stays visible whatever the stored hidden list
|
|
57
|
+
* says, so a stale list — a column that lost its hide capability while it was
|
|
58
|
+
* hidden — cannot strand the table without its select or name column.
|
|
59
|
+
*/
|
|
60
|
+
declare const visibleColumnIds: <TRender>(schema: TableSchema<TRender>, hiddenColumnIds: readonly string[]) => string[];
|
|
61
|
+
/** The starting width of every column, keyed by id. */
|
|
62
|
+
declare const tableColumnSizing: <TRender>(schema: TableSchema<TRender>) => Record<string, number>;
|
|
63
|
+
/**
|
|
64
|
+
* A duplicate column id silently drops a column: the table keys by id, so the
|
|
65
|
+
* second declaration wins and the first disappears with no error anywhere.
|
|
66
|
+
* Callers that build a schema from user data (a property list) check here.
|
|
67
|
+
*/
|
|
68
|
+
declare const duplicateColumnIds: <TRender>(schema: TableSchema<TRender>) => string[];
|
|
69
|
+
//#endregion
|
|
70
|
+
export { TableColumnCapabilities, TableColumnDescriptor, TableSchema, duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/data-table/schema.ts
|
|
2
|
+
/** Every column a schema declares, in order. */
|
|
3
|
+
const tableColumnIds = (schema) => schema.columns.map((column) => column.id);
|
|
4
|
+
const withCapability = (schema, capability) => schema.columns.filter((column) => column.capabilities[capability]).map((column) => column.id);
|
|
5
|
+
const sortableColumnIds = (schema) => withCapability(schema, "sort");
|
|
6
|
+
const hideableColumnIds = (schema) => withCapability(schema, "hide");
|
|
7
|
+
const findTableColumn = (schema, id) => schema.columns.find((column) => column.id === id);
|
|
8
|
+
/**
|
|
9
|
+
* Which columns a view shows.
|
|
10
|
+
*
|
|
11
|
+
* A column that cannot be hidden stays visible whatever the stored hidden list
|
|
12
|
+
* says, so a stale list — a column that lost its hide capability while it was
|
|
13
|
+
* hidden — cannot strand the table without its select or name column.
|
|
14
|
+
*/
|
|
15
|
+
const visibleColumnIds = (schema, hiddenColumnIds) => {
|
|
16
|
+
const hidden = new Set(hiddenColumnIds);
|
|
17
|
+
return schema.columns.filter((column) => !column.capabilities.hide || !hidden.has(column.id)).map((column) => column.id);
|
|
18
|
+
};
|
|
19
|
+
/** The starting width of every column, keyed by id. */
|
|
20
|
+
const tableColumnSizing = (schema) => {
|
|
21
|
+
const sizing = {};
|
|
22
|
+
for (const column of schema.columns) sizing[column.id] = column.size;
|
|
23
|
+
return sizing;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A duplicate column id silently drops a column: the table keys by id, so the
|
|
27
|
+
* second declaration wins and the first disappears with no error anywhere.
|
|
28
|
+
* Callers that build a schema from user data (a property list) check here.
|
|
29
|
+
*/
|
|
30
|
+
const duplicateColumnIds = (schema) => {
|
|
31
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
33
|
+
for (const column of schema.columns) {
|
|
34
|
+
if (seen.has(column.id)) duplicates.add(column.id);
|
|
35
|
+
seen.add(column.id);
|
|
36
|
+
}
|
|
37
|
+
return [...duplicates];
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { duplicateColumnIds, findTableColumn, hideableColumnIds, sortableColumnIds, tableColumnIds, tableColumnSizing, visibleColumnIds };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
//#region src/hooks/use-contained-handler.d.ts
|
|
3
|
+
type ContainmentRoot = {
|
|
4
|
+
contains: (target: Node) => boolean;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Wrap a React event handler so it only fires when the event target
|
|
8
|
+
* is a DOM descendant of the given ref.
|
|
9
|
+
*
|
|
10
|
+
* React forwards synthetic events through the parent React tree even
|
|
11
|
+
* when descendants are rendered via createPortal. That makes it unsafe
|
|
12
|
+
* for a parent element to attach `onMouseDown`, `onClick`, `onFocus`,
|
|
13
|
+
* etc. that side-effect (focus steal, preventDefault, selection changes)
|
|
14
|
+
* under the assumption "the target lives inside me" — a portaled popup
|
|
15
|
+
* (Dialog, Combobox, Tooltip) silently bypasses the DOM boundary and
|
|
16
|
+
* triggers the side effect, dismissing itself.
|
|
17
|
+
*
|
|
18
|
+
* Only use for event types whose `target` is the meaningful subject of
|
|
19
|
+
* the event: pointer/mouse/touch/click and `focus`. Do **not** wrap
|
|
20
|
+
* `onBlur`: blur's `target` is the element losing focus, not the new
|
|
21
|
+
* focus destination, so the containment test cannot answer "is focus
|
|
22
|
+
* leaving for a portaled child?". For that case test `relatedTarget`
|
|
23
|
+
* directly inside the handler.
|
|
24
|
+
*
|
|
25
|
+
* The `require-contained-handler` oxlint rule enforces this on any JSX
|
|
26
|
+
* element carrying both `ref={…}` and one of the watched handler props;
|
|
27
|
+
* `containedEventHandler` covers elements that do not otherwise need a ref.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const barRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
* return (
|
|
32
|
+
* <div
|
|
33
|
+
* ref={barRef}
|
|
34
|
+
* onMouseDown={containedHandler(barRef, (e) => {
|
|
35
|
+
* e.preventDefault();
|
|
36
|
+
* focusEditor();
|
|
37
|
+
* })}
|
|
38
|
+
* >
|
|
39
|
+
* ...
|
|
40
|
+
* </div>
|
|
41
|
+
* );
|
|
42
|
+
*/
|
|
43
|
+
declare const containedHandler: <E extends {
|
|
44
|
+
target: unknown;
|
|
45
|
+
}>(ref: React$1.RefObject<ContainmentRoot | null> | null | undefined, handler: ((event: E) => void) | undefined) => (event: E) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Contain a synchronous JSX handler to its own DOM subtree without a ref.
|
|
48
|
+
* Prefer this form when the element does not otherwise need a ref.
|
|
49
|
+
*/
|
|
50
|
+
declare const containedEventHandler: <E extends {
|
|
51
|
+
currentTarget: unknown;
|
|
52
|
+
target: unknown;
|
|
53
|
+
}>(handler: (event: E) => void) => (event: E) => void;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { containedEventHandler, containedHandler };
|