@stll/ui 0.0.1-placeholder.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +84 -0
  2. package/dist/components/accordion.d.ts +8 -0
  3. package/dist/components/accordion.js +38 -0
  4. package/dist/components/alert-dialog.d.ts +32 -0
  5. package/dist/components/alert-dialog.js +75 -0
  6. package/dist/components/avatar.d.ts +7 -0
  7. package/dist/components/avatar.js +22 -0
  8. package/dist/components/bidi-text.d.ts +24 -0
  9. package/dist/components/bidi-text.js +38 -0
  10. package/dist/components/brand-icons.d.ts +7 -0
  11. package/dist/components/brand-icons.js +18 -0
  12. package/dist/components/breadcrumb.d.ts +12 -0
  13. package/dist/components/breadcrumb.js +61 -0
  14. package/dist/components/button-variants.d.ts +17 -0
  15. package/dist/components/button-variants.js +43 -0
  16. package/dist/components/button.d.ts +20 -0
  17. package/dist/components/button.js +53 -0
  18. package/dist/components/checkbox.d.ts +5 -0
  19. package/dist/components/checkbox.js +44 -0
  20. package/dist/components/color-picker.d.ts +47 -0
  21. package/dist/components/color-picker.js +249 -0
  22. package/dist/components/combobox.d.ts +40 -0
  23. package/dist/components/combobox.js +208 -0
  24. package/dist/components/command.d.ts +34 -0
  25. package/dist/components/command.js +100 -0
  26. package/dist/components/date-picker-popover.d.ts +29 -0
  27. package/dist/components/date-picker-popover.js +548 -0
  28. package/dist/components/date-picker-popover.logic.d.ts +14 -0
  29. package/dist/components/date-picker-popover.logic.js +26 -0
  30. package/dist/components/destructive-action-confirmation.d.ts +21 -0
  31. package/dist/components/destructive-action-confirmation.js +60 -0
  32. package/dist/components/destructive-confirm-dialog.d.ts +17 -0
  33. package/dist/components/destructive-confirm-dialog.js +49 -0
  34. package/dist/components/dialog.d.ts +37 -0
  35. package/dist/components/dialog.js +92 -0
  36. package/dist/components/directional-icon.d.ts +30 -0
  37. package/dist/components/directional-icon.js +12 -0
  38. package/dist/components/field.d.ts +11 -0
  39. package/dist/components/field.js +34 -0
  40. package/dist/components/form.d.ts +5 -0
  41. package/dist/components/form.js +12 -0
  42. package/dist/components/frame.d.ts +10 -0
  43. package/dist/components/frame.js +35 -0
  44. package/dist/components/hex-color-picker.d.ts +11 -0
  45. package/dist/components/hex-color-picker.js +366 -0
  46. package/dist/components/input-group.d.ts +15 -0
  47. package/dist/components/input-group.js +53 -0
  48. package/dist/components/input-otp.d.ts +13 -0
  49. package/dist/components/input-otp.js +39 -0
  50. package/dist/components/input.d.ts +12 -0
  51. package/dist/components/input.js +46 -0
  52. package/dist/components/label.d.ts +5 -0
  53. package/dist/components/label.js +18 -0
  54. package/dist/components/menu.d.ts +44 -0
  55. package/dist/components/menu.js +152 -0
  56. package/dist/components/outline-rail.d.ts +39 -0
  57. package/dist/components/outline-rail.js +405 -0
  58. package/dist/components/pagination.d.ts +17 -0
  59. package/dist/components/pagination.js +78 -0
  60. package/dist/components/popover.d.ts +34 -0
  61. package/dist/components/popover.js +67 -0
  62. package/dist/components/preview-card.d.ts +12 -0
  63. package/dist/components/preview-card.js +25 -0
  64. package/dist/components/preview-pane.d.ts +23 -0
  65. package/dist/components/preview-pane.js +33 -0
  66. package/dist/components/scroll-area.d.ts +19 -0
  67. package/dist/components/scroll-area.js +38 -0
  68. package/dist/components/scroll-to-top.d.ts +12 -0
  69. package/dist/components/scroll-to-top.js +43 -0
  70. package/dist/components/secret-input.d.ts +9 -0
  71. package/dist/components/secret-input.js +38 -0
  72. package/dist/components/segmented-icon-toggle.d.ts +22 -0
  73. package/dist/components/segmented-icon-toggle.js +30 -0
  74. package/dist/components/select.d.ts +25 -0
  75. package/dist/components/select.js +196 -0
  76. package/dist/components/separator.d.ts +16 -0
  77. package/dist/components/separator.js +26 -0
  78. package/dist/components/sheet.d.ts +29 -0
  79. package/dist/components/sheet.js +87 -0
  80. package/dist/components/skeleton.d.ts +4 -0
  81. package/dist/components/skeleton.js +10 -0
  82. package/dist/components/stella-mark.d.ts +5 -0
  83. package/dist/components/stella-mark.js +12 -0
  84. package/dist/components/stella-wordmark.d.ts +5 -0
  85. package/dist/components/stella-wordmark.js +21 -0
  86. package/dist/components/table.d.ts +20 -0
  87. package/dist/components/table.js +80 -0
  88. package/dist/components/tabs.d.ts +11 -0
  89. package/dist/components/tabs.js +46 -0
  90. package/dist/components/textarea.d.ts +9 -0
  91. package/dist/components/textarea.js +31 -0
  92. package/dist/components/toast.d.ts +60 -0
  93. package/dist/components/toast.js +261 -0
  94. package/dist/components/tooltip-trigger-helper.d.ts +11 -0
  95. package/dist/components/tooltip-trigger-helper.js +14 -0
  96. package/dist/components/tooltip.d.ts +15 -0
  97. package/dist/components/tooltip.js +32 -0
  98. package/dist/hooks/use-contained-handler.d.ts +55 -0
  99. package/dist/hooks/use-contained-handler.js +54 -0
  100. package/dist/hooks/use-content-dir.d.ts +48 -0
  101. package/dist/hooks/use-content-dir.js +45 -0
  102. package/dist/hooks/use-mobile.d.ts +4 -0
  103. package/dist/hooks/use-mobile.js +16 -0
  104. package/dist/hooks/use-viewport-width.d.ts +5 -0
  105. package/dist/hooks/use-viewport-width.js +14 -0
  106. package/dist/index.d.ts +60 -0
  107. package/dist/index.js +59 -0
  108. package/dist/inspector/chrome.d.ts +72 -0
  109. package/dist/inspector/chrome.js +153 -0
  110. package/dist/inspector/dock.d.ts +48 -0
  111. package/dist/inspector/dock.js +36 -0
  112. package/dist/inspector/index.d.ts +6 -0
  113. package/dist/inspector/index.js +6 -0
  114. package/dist/inspector/layout-tokens.d.ts +28 -0
  115. package/dist/inspector/layout-tokens.js +28 -0
  116. package/dist/inspector/pane-width.d.ts +64 -0
  117. package/dist/inspector/pane-width.js +53 -0
  118. package/dist/inspector/use-pane-width.d.ts +99 -0
  119. package/dist/inspector/use-pane-width.js +149 -0
  120. package/dist/lib/button-disposition.d.ts +63 -0
  121. package/dist/lib/button-disposition.js +52 -0
  122. package/dist/lib/overlay-layer.d.ts +22 -0
  123. package/dist/lib/overlay-layer.js +21 -0
  124. package/dist/lib/tab-order.d.ts +15 -0
  125. package/dist/lib/tab-order.js +15 -0
  126. package/dist/lib/tooltip-content.d.ts +13 -0
  127. package/dist/lib/tooltip-content.js +12 -0
  128. package/dist/lib/utils.d.ts +20 -0
  129. package/dist/lib/utils.js +41 -0
  130. package/dist/lib/week.d.ts +25 -0
  131. package/dist/lib/week.js +40 -0
  132. package/dist/styles/theme.css +1209 -0
  133. package/package.json +506 -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,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 };
@@ -0,0 +1,54 @@
1
+ //#region src/hooks/use-contained-handler.ts
2
+ /**
3
+ * Wrap a React event handler so it only fires when the event target
4
+ * is a DOM descendant of the given ref.
5
+ *
6
+ * React forwards synthetic events through the parent React tree even
7
+ * when descendants are rendered via createPortal. That makes it unsafe
8
+ * for a parent element to attach `onMouseDown`, `onClick`, `onFocus`,
9
+ * etc. that side-effect (focus steal, preventDefault, selection changes)
10
+ * under the assumption "the target lives inside me" — a portaled popup
11
+ * (Dialog, Combobox, Tooltip) silently bypasses the DOM boundary and
12
+ * triggers the side effect, dismissing itself.
13
+ *
14
+ * Only use for event types whose `target` is the meaningful subject of
15
+ * the event: pointer/mouse/touch/click and `focus`. Do **not** wrap
16
+ * `onBlur`: blur's `target` is the element losing focus, not the new
17
+ * focus destination, so the containment test cannot answer "is focus
18
+ * leaving for a portaled child?". For that case test `relatedTarget`
19
+ * directly inside the handler.
20
+ *
21
+ * The `require-contained-handler` oxlint rule enforces this on any JSX
22
+ * element carrying both `ref={…}` and one of the watched handler props;
23
+ * `containedEventHandler` covers elements that do not otherwise need a ref.
24
+ *
25
+ * @example
26
+ * const barRef = useRef<HTMLDivElement>(null);
27
+ * return (
28
+ * <div
29
+ * ref={barRef}
30
+ * onMouseDown={containedHandler(barRef, (e) => {
31
+ * e.preventDefault();
32
+ * focusEditor();
33
+ * })}
34
+ * >
35
+ * ...
36
+ * </div>
37
+ * );
38
+ */
39
+ const containedHandler = (ref, handler) => (event) => {
40
+ if (handler === void 0) return;
41
+ const container = ref?.current ?? null;
42
+ if (container !== null && event.target instanceof Node && !container.contains(event.target)) return;
43
+ handler(event);
44
+ };
45
+ /**
46
+ * Contain a synchronous JSX handler to its own DOM subtree without a ref.
47
+ * Prefer this form when the element does not otherwise need a ref.
48
+ */
49
+ const containedEventHandler = (handler) => (event) => {
50
+ if (event.currentTarget instanceof Node && event.target instanceof Node && !event.currentTarget.contains(event.target)) return;
51
+ handler(event);
52
+ };
53
+ //#endregion
54
+ export { containedEventHandler, containedHandler };
@@ -0,0 +1,48 @@
1
+ //#region src/hooks/use-content-dir.d.ts
2
+ /**
3
+ * Resolve the `dir` for a free-text field so the caret and alignment follow
4
+ * the ambient UI direction while the field is empty, then switch to the typed
5
+ * content's own direction once the user starts writing.
6
+ *
7
+ * `dir="auto"` on its own is wrong for this: the bidi heuristic reads the
8
+ * field's *value*, and an empty value has no strong directional character, so
9
+ * it falls back to LTR — leaving the caret on the left even under an RTL UI.
10
+ * Here an empty field omits `dir` entirely (so it inherits the document
11
+ * direction: caret on the right in Arabic), and a non-empty field uses
12
+ * `dir="auto"` (Arabic content → RTL, Latin content → LTR, re-evaluated live).
13
+ *
14
+ * An explicit `dir="ltr"`/`dir="rtl"` is treated as a forced direction and
15
+ * returned unchanged (e.g. always-LTR numeric fields).
16
+ *
17
+ * Empty↔non-empty is the only transition that changes direction, so the
18
+ * uncontrolled path stores a boolean and the state setter no-ops (no re-render)
19
+ * on every keystroke that doesn't cross that boundary.
20
+ */
21
+ type FieldValue = string | number | readonly string[] | undefined;
22
+ type UseContentDirArgs = {
23
+ dir: string | undefined;
24
+ value: FieldValue;
25
+ defaultValue: FieldValue;
26
+ };
27
+ type UseContentDirResult = {
28
+ dir: "ltr" | "rtl" | "auto" | undefined;
29
+ /**
30
+ * Feed the field's current text on every change so the uncontrolled path can
31
+ * detect the empty↔non-empty transition. No-op for controlled fields, whose
32
+ * direction is derived from `value` on render.
33
+ */
34
+ trackValue: (text: string) => void;
35
+ };
36
+ declare const isStructuredInputType: (type: string | undefined) => boolean;
37
+ /**
38
+ * Content-derived direction for a controlled field value: `"auto"` when there
39
+ * is content, `undefined` when empty (so the field inherits the ambient UI
40
+ * direction — caret on the RTL side under Arabic). Use this for a raw
41
+ * `<input>`/`<textarea>` whose value you already control; the shared
42
+ * `<Input>`/`<Textarea>` apply it for you via `useContentDir`, which also
43
+ * tracks the empty↔non-empty transition for uncontrolled fields.
44
+ */
45
+ declare const contentDir: (value: FieldValue) => "auto" | undefined;
46
+ declare const useContentDir: ({ dir, value, defaultValue }: UseContentDirArgs) => UseContentDirResult;
47
+ //#endregion
48
+ export { contentDir, isStructuredInputType, useContentDir };
@@ -0,0 +1,45 @@
1
+ import { useState } from "react";
2
+ //#region src/hooks/use-content-dir.ts
3
+ const STRUCTURED_INPUT_TYPES = /* @__PURE__ */ new Set([
4
+ "email",
5
+ "url",
6
+ "tel",
7
+ "number",
8
+ "password",
9
+ "date",
10
+ "datetime-local",
11
+ "time",
12
+ "month",
13
+ "week"
14
+ ]);
15
+ const isStructuredInputType = (type) => type !== void 0 && STRUCTURED_INPUT_TYPES.has(type);
16
+ const hasText = (value) => {
17
+ if (typeof value === "string") return value.length > 0;
18
+ if (typeof value === "number") return true;
19
+ return Array.isArray(value) && value.length > 0;
20
+ };
21
+ /**
22
+ * Content-derived direction for a controlled field value: `"auto"` when there
23
+ * is content, `undefined` when empty (so the field inherits the ambient UI
24
+ * direction — caret on the RTL side under Arabic). Use this for a raw
25
+ * `<input>`/`<textarea>` whose value you already control; the shared
26
+ * `<Input>`/`<Textarea>` apply it for you via `useContentDir`, which also
27
+ * tracks the empty↔non-empty transition for uncontrolled fields.
28
+ */
29
+ const contentDir = (value) => hasText(value) ? "auto" : void 0;
30
+ const useContentDir = ({ dir, value, defaultValue }) => {
31
+ const forcedDir = dir === "ltr" || dir === "rtl" ? dir : void 0;
32
+ const isControlled = value !== void 0;
33
+ const [uncontrolledHasText, setUncontrolledHasText] = useState(() => hasText(defaultValue));
34
+ const contentPresent = isControlled ? hasText(value) : uncontrolledHasText;
35
+ return {
36
+ dir: forcedDir ?? (contentPresent ? "auto" : void 0),
37
+ trackValue: (text) => {
38
+ if (isControlled) return;
39
+ const next = text.length > 0;
40
+ setUncontrolledHasText((previous) => previous === next ? previous : next);
41
+ }
42
+ };
43
+ };
44
+ //#endregion
45
+ export { contentDir, isStructuredInputType, useContentDir };
@@ -0,0 +1,4 @@
1
+ //#region src/hooks/use-mobile.d.ts
2
+ declare function useIsMobile(): boolean;
3
+ //#endregion
4
+ export { useIsMobile };