beez-ui 0.7.0 → 0.8.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 (96) hide show
  1. package/CHANGELOG.md +21 -3
  2. package/README.md +290 -274
  3. package/dist/components/account-menu.d.ts +53 -0
  4. package/dist/components/account-menu.js +405 -0
  5. package/dist/components/animated-collapse.d.ts +19 -0
  6. package/dist/components/animated-collapse.js +81 -0
  7. package/dist/components/animated-count.d.ts +13 -0
  8. package/dist/components/animated-count.js +105 -0
  9. package/dist/components/animated-list-item.d.ts +25 -0
  10. package/dist/components/animated-list-item.js +132 -0
  11. package/dist/components/bouncing-dots-loader.d.ts +19 -0
  12. package/dist/components/bouncing-dots-loader.js +47 -0
  13. package/dist/components/confirm-delete-button.d.ts +29 -0
  14. package/dist/components/confirm-delete-button.js +254 -0
  15. package/dist/components/empty-state.d.ts +24 -0
  16. package/dist/components/empty-state.js +37 -0
  17. package/dist/components/error-state.d.ts +20 -0
  18. package/dist/components/error-state.js +145 -0
  19. package/dist/components/external-browser-handoff.d.ts +27 -0
  20. package/dist/components/external-browser-handoff.js +306 -0
  21. package/dist/components/file-upload.d.ts +78 -0
  22. package/dist/components/file-upload.js +678 -0
  23. package/dist/components/info-popover.d.ts +23 -0
  24. package/dist/components/info-popover.js +158 -0
  25. package/dist/components/month-calendar-header.d.ts +65 -0
  26. package/dist/components/month-calendar-header.js +337 -0
  27. package/dist/components/month-grid.d.ts +59 -0
  28. package/dist/components/month-grid.js +301 -0
  29. package/dist/components/notification-bell.d.ts +50 -0
  30. package/dist/components/notification-bell.js +338 -0
  31. package/dist/components/notification-panel.d.ts +56 -0
  32. package/dist/components/notification-panel.js +281 -0
  33. package/dist/components/open-in-browser-cta.d.ts +22 -0
  34. package/dist/components/open-in-browser-cta.js +61 -0
  35. package/dist/components/presence-swap.d.ts +22 -0
  36. package/dist/components/presence-swap.js +162 -0
  37. package/dist/components/progress-ring.d.ts +20 -0
  38. package/dist/components/progress-ring.js +53 -0
  39. package/dist/components/pwa-update-control.d.ts +18 -0
  40. package/dist/components/pwa-update-control.js +119 -0
  41. package/dist/components/reaction-button.d.ts +26 -0
  42. package/dist/components/reaction-button.js +114 -0
  43. package/dist/components/rich-link-editor.d.ts +25 -0
  44. package/dist/components/rich-link-editor.js +320 -0
  45. package/dist/components/rich-markdown-content.d.ts +10 -0
  46. package/dist/components/rich-markdown-content.js +56 -0
  47. package/dist/components/rich-text-content.d.ts +19 -0
  48. package/dist/components/rich-text-content.js +26 -0
  49. package/dist/emoji-picker.d.ts +27 -0
  50. package/dist/emoji-picker.js +283 -0
  51. package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
  52. package/dist/hooks/use-horizontal-swipe.js +80 -0
  53. package/dist/hooks/use-is-hydrated.d.ts +6 -0
  54. package/dist/hooks/use-is-hydrated.js +20 -0
  55. package/dist/hooks/use-minute-clock.d.ts +23 -0
  56. package/dist/hooks/use-minute-clock.js +147 -0
  57. package/dist/hooks/use-month-transition-direction.d.ts +21 -0
  58. package/dist/hooks/use-month-transition-direction.js +110 -0
  59. package/dist/hooks/use-rich-link-editor.d.ts +55 -0
  60. package/dist/hooks/use-rich-link-editor.js +515 -0
  61. package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
  62. package/dist/hooks/use-viewer-time-zone.js +20 -0
  63. package/dist/index.d.ts +44 -0
  64. package/dist/index.js +43 -0
  65. package/dist/lib/browser-clipboard.d.ts +13 -0
  66. package/dist/lib/browser-clipboard.js +48 -0
  67. package/dist/lib/browser-navigation.d.ts +21 -0
  68. package/dist/lib/browser-navigation.js +42 -0
  69. package/dist/lib/file-acceptance.d.ts +43 -0
  70. package/dist/lib/file-acceptance.js +107 -0
  71. package/dist/lib/format-file-size.d.ts +16 -0
  72. package/dist/lib/format-file-size.js +34 -0
  73. package/dist/lib/fuzzy-search.d.ts +17 -0
  74. package/dist/lib/fuzzy-search.js +183 -0
  75. package/dist/lib/horizontal-swipe.d.ts +23 -0
  76. package/dist/lib/horizontal-swipe.js +29 -0
  77. package/dist/lib/in-app-browser.d.ts +35 -0
  78. package/dist/lib/in-app-browser.js +80 -0
  79. package/dist/lib/month-grid.d.ts +42 -0
  80. package/dist/lib/month-grid.js +74 -0
  81. package/dist/lib/name-initials.d.ts +7 -0
  82. package/dist/lib/name-initials.js +11 -0
  83. package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
  84. package/dist/lib/rich-text/link-markdown-constants.js +458 -0
  85. package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
  86. package/dist/lib/rich-text/link-markdown-types.js +1 -0
  87. package/dist/lib/rich-text/link-markdown.d.ts +193 -0
  88. package/dist/lib/rich-text/link-markdown.js +592 -0
  89. package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
  90. package/dist/lib/rich-text/rich-markdown.js +105 -0
  91. package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
  92. package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
  93. package/dist/motion/tokens.d.ts +17 -1
  94. package/dist/motion/tokens.js +17 -1
  95. package/dist/styles.css +1 -1
  96. package/package.json +211 -1
@@ -0,0 +1,132 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ import { motion, useIsPresent } from "motion/react";
4
+ import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
5
+ import { cn } from "../lib/utils.js";
6
+ import { MOTION_EASE, MOTION_ITEM_ENTER_SCALE, MOTION_LIST_ITEM_DISTANCE, MOTION_TIMING, SPRING_LAYOUT } from "../motion/tokens.js";
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ const ANIMATED_LIST_ITEM_ELEMENTS = {
9
+ li: motion.li,
10
+ div: motion.div,
11
+ article: motion.article
12
+ };
13
+ const LIST_ITEM_TRANSITION = {
14
+ duration: MOTION_TIMING.panel,
15
+ ease: MOTION_EASE,
16
+ layout: SPRING_LAYOUT
17
+ };
18
+ const LIST_ITEM_EXIT_TRANSITION = {
19
+ duration: MOTION_TIMING.exit,
20
+ ease: MOTION_EASE
21
+ };
22
+ /** Reduced motion keeps enter/exit semantics (inert while leaving) but without travel or delay. */
23
+ const INSTANT_TRANSITION = { duration: 0 };
24
+ /**
25
+ * Wrap the list in `<AnimatePresence initial={false}>` so only items added after the
26
+ * first render animate in, and removed items animate out before leaving the DOM.
27
+ * A leaving item turns inert and hidden from assistive technology, so it can no
28
+ * longer be focused, clicked or announced during its exit.
29
+ * @param props - Native attributes, element type and content.
30
+ * @returns The animated item.
31
+ */
32
+ export function AnimatedListItem(t0) {
33
+ const $ = _c(22);
34
+ let children;
35
+ let className;
36
+ let elementProps;
37
+ let t1;
38
+ let t2;
39
+ if ($[0] !== t0) {
40
+ ({children, as: t1, layout: t2, className, ...elementProps} = t0);
41
+ $[0] = t0;
42
+ $[1] = children;
43
+ $[2] = className;
44
+ $[3] = elementProps;
45
+ $[4] = t1;
46
+ $[5] = t2;
47
+ } else {
48
+ children = $[1];
49
+ className = $[2];
50
+ elementProps = $[3];
51
+ t1 = $[4];
52
+ t2 = $[5];
53
+ }
54
+ const as = t1 === undefined ? "li" : t1;
55
+ const layout = t2 === undefined ? true : t2;
56
+ const MotionElement = ANIMATED_LIST_ITEM_ELEMENTS[as];
57
+ const isPresent = useIsPresent();
58
+ const shouldReduceMotion = usePrefersReducedMotion();
59
+ const t3 = isPresent ? elementProps["aria-hidden"] : true;
60
+ const t4 = !isPresent || undefined;
61
+ let t5;
62
+ if ($[6] !== className) {
63
+ t5 = cn("min-w-0", className);
64
+ $[6] = className;
65
+ $[7] = t5;
66
+ } else {
67
+ t5 = $[7];
68
+ }
69
+ const t6 = layout && !shouldReduceMotion ? "position" : false;
70
+ let t7;
71
+ let t8;
72
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
73
+ t7 = {
74
+ opacity: 0,
75
+ y: MOTION_LIST_ITEM_DISTANCE,
76
+ scale: MOTION_ITEM_ENTER_SCALE
77
+ };
78
+ t8 = {
79
+ opacity: 1,
80
+ y: 0,
81
+ scale: 1
82
+ };
83
+ $[8] = t7;
84
+ $[9] = t8;
85
+ } else {
86
+ t7 = $[8];
87
+ t8 = $[9];
88
+ }
89
+ const t9 = shouldReduceMotion ? INSTANT_TRANSITION : LIST_ITEM_EXIT_TRANSITION;
90
+ let t10;
91
+ if ($[10] !== t9) {
92
+ t10 = {
93
+ opacity: 0,
94
+ scale: MOTION_ITEM_ENTER_SCALE,
95
+ transition: t9
96
+ };
97
+ $[10] = t9;
98
+ $[11] = t10;
99
+ } else {
100
+ t10 = $[11];
101
+ }
102
+ const t11 = shouldReduceMotion ? INSTANT_TRANSITION : LIST_ITEM_TRANSITION;
103
+ let t12;
104
+ if ($[12] !== MotionElement || $[13] !== children || $[14] !== elementProps || $[15] !== t10 || $[16] !== t11 || $[17] !== t3 || $[18] !== t4 || $[19] !== t5 || $[20] !== t6) {
105
+ t12 = /* @__PURE__ */ _jsx(MotionElement, {
106
+ "data-slot": "animated-list-item",
107
+ ...elementProps,
108
+ "aria-hidden": t3,
109
+ inert: t4,
110
+ className: t5,
111
+ layout: t6,
112
+ initial: t7,
113
+ animate: t8,
114
+ exit: t10,
115
+ transition: t11,
116
+ children
117
+ });
118
+ $[12] = MotionElement;
119
+ $[13] = children;
120
+ $[14] = elementProps;
121
+ $[15] = t10;
122
+ $[16] = t11;
123
+ $[17] = t3;
124
+ $[18] = t4;
125
+ $[19] = t5;
126
+ $[20] = t6;
127
+ $[21] = t12;
128
+ } else {
129
+ t12 = $[21];
130
+ }
131
+ return t12;
132
+ }
@@ -0,0 +1,19 @@
1
+ /** Animated three-dot bouncing loader with synchronized floor shadows. */
2
+ import type { HTMLAttributes } from "react";
3
+ export type BouncingDotsLoaderSize = "sm" | "md";
4
+ export type BouncingDotsLoaderProps = Omit<HTMLAttributes<HTMLDivElement>, "aria-label" | "role"> & {
5
+ /**
6
+ * Accessible label announced by assistive technologies. Also rendered as visually hidden text
7
+ * so screen readers can read it independently of the `aria-label`.
8
+ */
9
+ label?: string;
10
+ /** Use `"sm"` for inline or compact contexts and `"md"` (default) for standalone loading panels. */
11
+ size?: BouncingDotsLoaderSize;
12
+ };
13
+ /**
14
+ * Renders the loader as a `role="status"` region. It fades in after a short delay, so loads that
15
+ * finish quickly never flash it. Reduced motion stops the bounce through the shared fallback.
16
+ * @param props - Label, size and native attributes.
17
+ * @returns The loader.
18
+ */
19
+ export declare function BouncingDotsLoader({ label, size, className, ...rest }: BouncingDotsLoaderProps): import("react").JSX.Element;
@@ -0,0 +1,47 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ const DEFAULT_LOADING_LABEL = "Cargando...";
4
+ /** Stage, dot and shadow geometry per size; the keyframes in `keyframes.css` match these values. */
5
+ const LOADER_SIZE_CLASS_NAMES = {
6
+ md: {
7
+ stage: "h-[3.75rem] w-[12.5rem]",
8
+ dot: "size-5 animate-[beez-bouncing-dot-md_0.5s_ease_infinite_alternate]",
9
+ shadow: "top-[3.875rem] h-1 w-5"
10
+ },
11
+ sm: {
12
+ stage: "h-[1.875rem] w-[6.5rem]",
13
+ dot: "size-2.5 animate-[beez-bouncing-dot-sm_0.5s_ease_infinite_alternate]",
14
+ shadow: "top-[1.9375rem] h-[0.1875rem] w-2.5"
15
+ }
16
+ };
17
+ /** Horizontal slot and phase of each dot: the middle and right dots trail the left one. */
18
+ const DOT_POSITION_CLASS_NAMES = [
19
+ "left-[15%]",
20
+ "left-[45%] delay-200",
21
+ "right-[15%] delay-300"
22
+ ];
23
+ /**
24
+ * Renders the loader as a `role="status"` region. It fades in after a short delay, so loads that
25
+ * finish quickly never flash it. Reduced motion stops the bounce through the shared fallback.
26
+ * @param props - Label, size and native attributes.
27
+ * @returns The loader.
28
+ */
29
+ export function BouncingDotsLoader({ label = DEFAULT_LOADING_LABEL, size = "md", className, ...rest }) {
30
+ const sizeClassNames = LOADER_SIZE_CLASS_NAMES[size];
31
+ return /* @__PURE__ */ _jsxs("div", {
32
+ "data-slot": "bouncing-dots-loader",
33
+ "data-size": size,
34
+ ...rest,
35
+ "aria-label": label,
36
+ role: "status",
37
+ className: cn("flex w-full items-center justify-center animate-in fade-in fill-mode-both delay-120 duration-300", className),
38
+ children: [/* @__PURE__ */ _jsxs("div", {
39
+ "aria-hidden": "true",
40
+ className: cn("relative z-[1]", sizeClassNames.stage),
41
+ children: [DOT_POSITION_CLASS_NAMES.map((positionClassName) => /* @__PURE__ */ _jsx("span", { className: cn("absolute top-0 origin-bottom rounded-full bg-foreground", sizeClassNames.dot, positionClassName) }, `dot-${positionClassName}`)), DOT_POSITION_CLASS_NAMES.map((positionClassName) => /* @__PURE__ */ _jsx("span", { className: cn("absolute -z-[1] rounded-full bg-foreground/35 blur-[1px] animate-[beez-bouncing-dot-shadow_0.5s_ease_infinite_alternate]", sizeClassNames.shadow, positionClassName) }, `shadow-${positionClassName}`))]
42
+ }), /* @__PURE__ */ _jsx("span", {
43
+ className: "sr-only",
44
+ children: label
45
+ })]
46
+ });
47
+ }
@@ -0,0 +1,29 @@
1
+ /** Row action menu whose destructive item asks for an inline confirmation before running. */
2
+ import { type ReactNode } from "react";
3
+ export interface ConfirmDeleteButtonLabels {
4
+ /** Dismisses the confirmation. */
5
+ cancel?: string;
6
+ /** Runs `onConfirm`. */
7
+ confirm?: string;
8
+ /** Destructive menu item that opens the confirmation. */
9
+ delete?: string;
10
+ /** Accessible name of the icon-only menu trigger. */
11
+ menu?: string;
12
+ }
13
+ export interface ConfirmDeleteButtonProps {
14
+ /** Question shown in the confirmation, also used as its accessible name. */
15
+ message: string;
16
+ onConfirm: () => void;
17
+ /** Extra menu items (for example Edit), rendered before the delete item. */
18
+ extraMenuItems?: ReactNode;
19
+ labels?: ConfirmDeleteButtonLabels;
20
+ className?: string;
21
+ }
22
+ /**
23
+ * Renders an icon menu with a destructive item. Choosing it opens a confirmation anchored to
24
+ * the trigger; only its confirm button runs `onConfirm`. Escape, an outside click or Cancel
25
+ * dismiss it without side effects.
26
+ * @param props - Confirmation copy, callback, extra items and optional labels.
27
+ * @returns The menu trigger with its confirmation.
28
+ */
29
+ export declare function ConfirmDeleteButton({ message, onConfirm, extraMenuItems, labels, className, }: ConfirmDeleteButtonProps): import("react").JSX.Element;
@@ -0,0 +1,254 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ /** Row action menu whose destructive item asks for an inline confirmation before running. */
4
+ import { useId, useRef, useState } from "react";
5
+ import { MoreVertical, Trash2 } from "lucide-react";
6
+ import { cn } from "../lib/utils.js";
7
+ import { Button } from "./button.js";
8
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./dropdown-menu.js";
9
+ import { Popover, PopoverAnchor, PopoverContent } from "./popover.js";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const CONFIRM_DELETE_DEFAULT_LABELS = {
12
+ cancel: "Cancelar",
13
+ confirm: "Confirmar",
14
+ delete: "Eliminar",
15
+ menu: "Abrir acciones"
16
+ };
17
+ /**
18
+ * Renders an icon menu with a destructive item. Choosing it opens a confirmation anchored to
19
+ * the trigger; only its confirm button runs `onConfirm`. Escape, an outside click or Cancel
20
+ * dismiss it without side effects.
21
+ * @param props - Confirmation copy, callback, extra items and optional labels.
22
+ * @returns The menu trigger with its confirmation.
23
+ */
24
+ export function ConfirmDeleteButton(t0) {
25
+ const $ = _c(43);
26
+ const { message, onConfirm, extraMenuItems: t1, labels, className } = t0;
27
+ const extraMenuItems = t1 === undefined ? null : t1;
28
+ let t2;
29
+ if ($[0] !== labels) {
30
+ t2 = {
31
+ ...CONFIRM_DELETE_DEFAULT_LABELS,
32
+ ...labels
33
+ };
34
+ $[0] = labels;
35
+ $[1] = t2;
36
+ } else {
37
+ t2 = $[1];
38
+ }
39
+ const resolvedLabels = t2;
40
+ const [isConfirming, setIsConfirming] = useState(false);
41
+ const isOpeningConfirmationRef = useRef(false);
42
+ const messageId = useId();
43
+ let t3;
44
+ if ($[2] !== className) {
45
+ t3 = cn("inline-flex justify-end", className);
46
+ $[2] = className;
47
+ $[3] = t3;
48
+ } else {
49
+ t3 = $[3];
50
+ }
51
+ let t4;
52
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
53
+ t4 = /* @__PURE__ */ _jsx(MoreVertical, { "aria-hidden": "true" });
54
+ $[4] = t4;
55
+ } else {
56
+ t4 = $[4];
57
+ }
58
+ let t5;
59
+ if ($[5] !== resolvedLabels.menu) {
60
+ t5 = /* @__PURE__ */ _jsx(PopoverAnchor, {
61
+ asChild: true,
62
+ children: /* @__PURE__ */ _jsx(DropdownMenuTrigger, {
63
+ asChild: true,
64
+ children: /* @__PURE__ */ _jsx(Button, {
65
+ "aria-label": resolvedLabels.menu,
66
+ size: "icon-sm",
67
+ type: "button",
68
+ variant: "ghost",
69
+ children: t4
70
+ })
71
+ })
72
+ });
73
+ $[5] = resolvedLabels.menu;
74
+ $[6] = t5;
75
+ } else {
76
+ t5 = $[6];
77
+ }
78
+ let t6;
79
+ if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
80
+ t6 = (event) => {
81
+ if (!isOpeningConfirmationRef.current) {
82
+ return;
83
+ }
84
+ isOpeningConfirmationRef.current = false;
85
+ event.preventDefault();
86
+ };
87
+ $[7] = t6;
88
+ } else {
89
+ t6 = $[7];
90
+ }
91
+ let t7;
92
+ let t8;
93
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
94
+ t7 = () => {
95
+ isOpeningConfirmationRef.current = true;
96
+ setIsConfirming(true);
97
+ };
98
+ t8 = /* @__PURE__ */ _jsx(Trash2, { "aria-hidden": "true" });
99
+ $[8] = t7;
100
+ $[9] = t8;
101
+ } else {
102
+ t7 = $[8];
103
+ t8 = $[9];
104
+ }
105
+ let t9;
106
+ if ($[10] !== resolvedLabels.delete) {
107
+ t9 = /* @__PURE__ */ _jsxs(DropdownMenuItem, {
108
+ variant: "destructive",
109
+ onSelect: t7,
110
+ children: [t8, resolvedLabels.delete]
111
+ });
112
+ $[10] = resolvedLabels.delete;
113
+ $[11] = t9;
114
+ } else {
115
+ t9 = $[11];
116
+ }
117
+ let t10;
118
+ if ($[12] !== extraMenuItems || $[13] !== t9) {
119
+ t10 = /* @__PURE__ */ _jsxs(DropdownMenuContent, {
120
+ align: "end",
121
+ onCloseAutoFocus: t6,
122
+ children: [extraMenuItems, t9]
123
+ });
124
+ $[12] = extraMenuItems;
125
+ $[13] = t9;
126
+ $[14] = t10;
127
+ } else {
128
+ t10 = $[14];
129
+ }
130
+ let t11;
131
+ if ($[15] !== t10 || $[16] !== t5) {
132
+ t11 = /* @__PURE__ */ _jsxs(DropdownMenu, { children: [t5, t10] });
133
+ $[15] = t10;
134
+ $[16] = t5;
135
+ $[17] = t11;
136
+ } else {
137
+ t11 = $[17];
138
+ }
139
+ let t12;
140
+ if ($[18] !== message || $[19] !== messageId) {
141
+ t12 = /* @__PURE__ */ _jsx("p", {
142
+ id: messageId,
143
+ className: "m-0 text-sm text-foreground",
144
+ children: message
145
+ });
146
+ $[18] = message;
147
+ $[19] = messageId;
148
+ $[20] = t12;
149
+ } else {
150
+ t12 = $[20];
151
+ }
152
+ let t13;
153
+ if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
154
+ t13 = () => setIsConfirming(false);
155
+ $[21] = t13;
156
+ } else {
157
+ t13 = $[21];
158
+ }
159
+ let t14;
160
+ if ($[22] !== resolvedLabels.cancel) {
161
+ t14 = /* @__PURE__ */ _jsx(Button, {
162
+ size: "sm",
163
+ type: "button",
164
+ variant: "outline",
165
+ onClick: t13,
166
+ children: resolvedLabels.cancel
167
+ });
168
+ $[22] = resolvedLabels.cancel;
169
+ $[23] = t14;
170
+ } else {
171
+ t14 = $[23];
172
+ }
173
+ let t15;
174
+ if ($[24] !== onConfirm) {
175
+ t15 = () => {
176
+ setIsConfirming(false);
177
+ onConfirm();
178
+ };
179
+ $[24] = onConfirm;
180
+ $[25] = t15;
181
+ } else {
182
+ t15 = $[25];
183
+ }
184
+ let t16;
185
+ if ($[26] !== resolvedLabels.confirm || $[27] !== t15) {
186
+ t16 = /* @__PURE__ */ _jsx(Button, {
187
+ size: "sm",
188
+ type: "button",
189
+ variant: "destructive",
190
+ onClick: t15,
191
+ children: resolvedLabels.confirm
192
+ });
193
+ $[26] = resolvedLabels.confirm;
194
+ $[27] = t15;
195
+ $[28] = t16;
196
+ } else {
197
+ t16 = $[28];
198
+ }
199
+ let t17;
200
+ if ($[29] !== t14 || $[30] !== t16) {
201
+ t17 = /* @__PURE__ */ _jsxs("div", {
202
+ className: "flex items-center gap-2",
203
+ children: [t14, t16]
204
+ });
205
+ $[29] = t14;
206
+ $[30] = t16;
207
+ $[31] = t17;
208
+ } else {
209
+ t17 = $[31];
210
+ }
211
+ let t18;
212
+ if ($[32] !== messageId || $[33] !== t12 || $[34] !== t17) {
213
+ t18 = /* @__PURE__ */ _jsxs(PopoverContent, {
214
+ align: "end",
215
+ "aria-labelledby": messageId,
216
+ className: "w-[min(18rem,calc(100vw-2rem))] gap-3 p-3.5",
217
+ children: [t12, t17]
218
+ });
219
+ $[32] = messageId;
220
+ $[33] = t12;
221
+ $[34] = t17;
222
+ $[35] = t18;
223
+ } else {
224
+ t18 = $[35];
225
+ }
226
+ let t19;
227
+ if ($[36] !== isConfirming || $[37] !== t11 || $[38] !== t18) {
228
+ t19 = /* @__PURE__ */ _jsxs(Popover, {
229
+ open: isConfirming,
230
+ onOpenChange: setIsConfirming,
231
+ children: [t11, t18]
232
+ });
233
+ $[36] = isConfirming;
234
+ $[37] = t11;
235
+ $[38] = t18;
236
+ $[39] = t19;
237
+ } else {
238
+ t19 = $[39];
239
+ }
240
+ let t20;
241
+ if ($[40] !== t19 || $[41] !== t3) {
242
+ t20 = /* @__PURE__ */ _jsx("div", {
243
+ "data-slot": "confirm-delete-button",
244
+ className: t3,
245
+ children: t19
246
+ });
247
+ $[40] = t19;
248
+ $[41] = t3;
249
+ $[42] = t20;
250
+ } else {
251
+ t20 = $[42];
252
+ }
253
+ return t20;
254
+ }
@@ -0,0 +1,24 @@
1
+ /** Placeholder for regions without content yet: empty lists, sections in construction or first steps. */
2
+ import type { ReactNode } from "react";
3
+ export type EmptyStateTitleElement = "h1" | "h2" | "h3" | "p";
4
+ export interface EmptyStateProps {
5
+ title: ReactNode;
6
+ /** Heading level that fits the surrounding outline; a paragraph for minor regions. */
7
+ titleAs?: EmptyStateTitleElement;
8
+ /** Short uppercase label above the title, such as "Próximamente". */
9
+ eyebrow?: ReactNode;
10
+ description?: ReactNode;
11
+ /** Actions or extra content, such as buttons or a template list. */
12
+ children?: ReactNode;
13
+ align?: "start" | "center";
14
+ /** `page` uses display typography for full sections; `inline` stays compact inside panels. */
15
+ size?: "page" | "inline";
16
+ className?: string;
17
+ }
18
+ /**
19
+ * Renders the empty region as a labelled section. It does not add a landmark besides the
20
+ * section, so it composes inside an existing `main`.
21
+ * @param props - Title, optional eyebrow, description, actions and layout.
22
+ * @returns The empty state.
23
+ */
24
+ export declare function EmptyState({ title, titleAs: TitleElement, eyebrow, description, children, align, size, className, }: EmptyStateProps): import("react").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /** Copy settles in one line after another; reduced motion drops it through the shared fallback. */
4
+ const ENTER_CLASS_NAME = "animate-in fade-in slide-in-from-bottom-1.5 fill-mode-both duration-300";
5
+ /**
6
+ * Renders the empty region as a labelled section. It does not add a landmark besides the
7
+ * section, so it composes inside an existing `main`.
8
+ * @param props - Title, optional eyebrow, description, actions and layout.
9
+ * @returns The empty state.
10
+ */
11
+ export function EmptyState({ title, titleAs: TitleElement = "h2", eyebrow, description, children, align = "start", size = "inline", className }) {
12
+ const isCentered = align === "center";
13
+ const isPage = size === "page";
14
+ return /* @__PURE__ */ _jsxs("section", {
15
+ "data-slot": "empty-state",
16
+ "data-size": size,
17
+ className: cn("grid gap-2", isCentered ? "justify-items-center text-center" : "justify-items-start", isPage ? "max-w-2xl gap-2.5 py-6" : "py-6", className),
18
+ children: [
19
+ eyebrow ? /* @__PURE__ */ _jsx("p", {
20
+ className: cn("m-0 text-[0.78rem] font-bold tracking-[0.08em] text-[color-mix(in_oklab,var(--primary)_76%,var(--foreground))] uppercase", ENTER_CLASS_NAME),
21
+ children: eyebrow
22
+ }) : null,
23
+ /* @__PURE__ */ _jsx(TitleElement, {
24
+ className: cn("m-0 text-balance [overflow-wrap:anywhere]", isPage ? "font-display text-[clamp(2rem,6vw,4rem)] leading-[1.05] font-semibold" : "font-semibold", ENTER_CLASS_NAME, "delay-40"),
25
+ children: title
26
+ }),
27
+ description ? /* @__PURE__ */ _jsx("p", {
28
+ className: cn("m-0 max-w-xl text-pretty text-muted-foreground", isPage && "text-[clamp(1rem,2vw,1.15rem)] leading-relaxed", ENTER_CLASS_NAME, "delay-80"),
29
+ children: description
30
+ }) : null,
31
+ children ? /* @__PURE__ */ _jsx("div", {
32
+ className: cn("mt-2 flex w-full flex-wrap gap-2", isCentered && "justify-center", ENTER_CLASS_NAME, "delay-120"),
33
+ children
34
+ }) : null
35
+ ]
36
+ });
37
+ }
@@ -0,0 +1,20 @@
1
+ /** Full-page recovery view for route and global error boundaries: explains the failure and offers a retry. */
2
+ import type { ReactNode } from "react";
3
+ export interface ErrorStateProps {
4
+ eyebrow?: ReactNode;
5
+ title: ReactNode;
6
+ description: ReactNode;
7
+ retryLabel: string;
8
+ onRetry: () => void;
9
+ /** Destination of the secondary action. Without it, only the retry action is shown. */
10
+ homeHref?: string;
11
+ homeLabel?: string;
12
+ className?: string;
13
+ }
14
+ /**
15
+ * Renders a full-height section with the error copy, a retry button and an optional way home.
16
+ * The home link uses the router adapter configured in `BeezUIProvider`.
17
+ * @param props - Copy, retry callback and optional home destination.
18
+ * @returns The error view.
19
+ */
20
+ export declare function ErrorState({ eyebrow, title, description, retryLabel, onRetry, homeHref, homeLabel, className }: ErrorStateProps): import("react").JSX.Element;