@neasg/design-system 0.4.8 → 0.4.10

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 (115) hide show
  1. package/README.md +14 -14
  2. package/dist/alert.d.ts +21 -2
  3. package/dist/alert.js +10 -3
  4. package/dist/avatar.d.ts +5 -2
  5. package/dist/avatar.js +76 -8
  6. package/dist/back-button.d.ts +2 -0
  7. package/dist/back-button.js +1 -1
  8. package/dist/badge.d.ts +3 -2
  9. package/dist/badge.js +9 -3
  10. package/dist/breadcrumb.js +2 -1
  11. package/dist/button.d.ts +1 -1
  12. package/dist/button.js +12 -9
  13. package/dist/calendar.js +10 -9
  14. package/dist/card.d.ts +29 -1
  15. package/dist/card.js +61 -7
  16. package/dist/checkbox.d.ts +2 -0
  17. package/dist/checkbox.js +9 -3
  18. package/dist/close-button.d.ts +6 -0
  19. package/dist/close-button.js +8 -0
  20. package/dist/collapsible.d.ts +7 -1
  21. package/dist/collapsible.js +2 -2
  22. package/dist/command-search.d.ts +16 -1
  23. package/dist/command-search.js +42 -16
  24. package/dist/command.js +3 -3
  25. package/dist/copy-button.d.ts +3 -1
  26. package/dist/copy-button.js +4 -2
  27. package/dist/count-badge.d.ts +3 -1
  28. package/dist/count-badge.js +10 -5
  29. package/dist/date-input.d.ts +18 -3
  30. package/dist/date-input.js +94 -21
  31. package/dist/dialog-primitive.js +4 -3
  32. package/dist/draggable-tabs.d.ts +7 -0
  33. package/dist/draggable-tabs.js +6 -5
  34. package/dist/drawer.js +2 -2
  35. package/dist/dropdown-button.d.ts +18 -0
  36. package/dist/dropdown-button.js +31 -0
  37. package/dist/edit-button.d.ts +10 -0
  38. package/dist/edit-button.js +7 -0
  39. package/dist/editable-table.d.ts +3 -1
  40. package/dist/editable-table.js +25 -12
  41. package/dist/field.d.ts +7 -3
  42. package/dist/field.js +8 -4
  43. package/dist/file-upload-status-toast.d.ts +28 -0
  44. package/dist/file-upload-status-toast.js +136 -0
  45. package/dist/file-upload.js +8 -7
  46. package/dist/filter-popover.d.ts +37 -0
  47. package/dist/filter-popover.js +73 -0
  48. package/dist/filter-toggle.js +2 -2
  49. package/dist/index.d.ts +45 -14
  50. package/dist/index.js +19 -4
  51. package/dist/input-control.d.ts +3 -2
  52. package/dist/input-control.js +3 -2
  53. package/dist/label-value-grid.d.ts +4 -2
  54. package/dist/label-value-grid.js +7 -6
  55. package/dist/label-value.js +3 -1
  56. package/dist/layout-right-panel-edge.d.ts +6 -0
  57. package/dist/layout-right-panel-edge.js +6 -0
  58. package/dist/layout.d.ts +77 -5
  59. package/dist/layout.js +439 -35
  60. package/dist/lib/date-utils.d.ts +10 -2
  61. package/dist/lib/date-utils.js +91 -11
  62. package/dist/lib/utils.js +8 -1
  63. package/dist/link.js +2 -2
  64. package/dist/message-item.d.ts +62 -0
  65. package/dist/message-item.js +148 -0
  66. package/dist/multi-select.js +31 -5
  67. package/dist/notification.d.ts +82 -0
  68. package/dist/notification.js +121 -0
  69. package/dist/otp-input.js +1 -1
  70. package/dist/page-header.js +1 -1
  71. package/dist/page-section.d.ts +2 -1
  72. package/dist/page-section.js +4 -3
  73. package/dist/pagination.js +2 -2
  74. package/dist/popover-menu.d.ts +23 -1
  75. package/dist/popover-menu.js +75 -5
  76. package/dist/popover-primitive.js +1 -1
  77. package/dist/progress.d.ts +5 -2
  78. package/dist/progress.js +6 -3
  79. package/dist/radio-group.d.ts +27 -0
  80. package/dist/radio-group.js +50 -0
  81. package/dist/rich-text-editor.d.ts +56 -0
  82. package/dist/rich-text-editor.js +394 -0
  83. package/dist/routing-timeline.d.ts +22 -0
  84. package/dist/routing-timeline.js +58 -0
  85. package/dist/scroll-hint.d.ts +8 -0
  86. package/dist/scroll-hint.js +7 -0
  87. package/dist/search-input-shell.js +1 -1
  88. package/dist/search-input.js +2 -2
  89. package/dist/section-nav.js +4 -4
  90. package/dist/select-primitive.js +3 -3
  91. package/dist/select.js +1 -1
  92. package/dist/skeleton.js +1 -1
  93. package/dist/styles.css +241 -55
  94. package/dist/table-column-visibility.d.ts +21 -0
  95. package/dist/table-column-visibility.js +74 -0
  96. package/dist/table-toolbar.js +1 -1
  97. package/dist/table.d.ts +12 -1
  98. package/dist/table.js +67 -33
  99. package/dist/tabs.d.ts +14 -3
  100. package/dist/tabs.js +60 -6
  101. package/dist/tailwind-preset.js +46 -0
  102. package/dist/task-mode-shell.d.ts +24 -0
  103. package/dist/task-mode-shell.js +110 -0
  104. package/dist/textarea.js +2 -1
  105. package/dist/theme-switcher.d.ts +28 -0
  106. package/dist/theme-switcher.js +27 -0
  107. package/dist/theme.d.ts +167 -0
  108. package/dist/theme.js +112 -0
  109. package/dist/toaster.js +5 -4
  110. package/dist/tooltip.js +1 -1
  111. package/dist/typography.d.ts +1 -1
  112. package/dist/typography.js +5 -5
  113. package/dist/workspace-header.d.ts +13 -0
  114. package/dist/workspace-header.js +11 -0
  115. package/package.json +18 -2
@@ -2,26 +2,41 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { format, parse } from "date-fns";
5
+ import { CalendarIcon } from "lucide-react";
5
6
  import { Calendar } from "./calendar";
6
7
  import { inputControlClassName } from "./input-control";
7
8
  import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
8
9
  import { PopoverContent, PopoverRoot, PopoverTrigger } from "./popover-primitive";
9
10
  import { cn } from "./lib/utils";
11
+ function createLocalDate(year, monthIndex, day) {
12
+ const date = new Date(year, monthIndex, day);
13
+ if (date.getFullYear() !== year ||
14
+ date.getMonth() !== monthIndex ||
15
+ date.getDate() !== day) {
16
+ return undefined;
17
+ }
18
+ return date;
19
+ }
10
20
  function parseDateString(dateStr) {
11
21
  if (!(dateStr === null || dateStr === void 0 ? void 0 : dateStr.trim()))
12
22
  return undefined;
13
23
  try {
14
- const nativeDate = new Date(dateStr);
15
- if (!isNaN(nativeDate.getTime()))
16
- return nativeDate;
17
- const ddmmyyyyMatch = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
24
+ const normalizedDateStr = dateStr.trim();
25
+ const isoDateMatch = normalizedDateStr.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
26
+ if (isoDateMatch) {
27
+ const [, year, month, day] = isoDateMatch;
28
+ return createLocalDate(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10));
29
+ }
30
+ const ddmmyyyyMatch = normalizedDateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
18
31
  if (ddmmyyyyMatch) {
19
32
  const [, day, month, year] = ddmmyyyyMatch;
20
- const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
21
- if (!isNaN(date.getTime()))
22
- return date;
33
+ return createLocalDate(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10));
23
34
  }
24
- const date = parse(dateStr, "yyyy-MM-dd", new Date());
35
+ const nativeDate = new Date(normalizedDateStr);
36
+ if (!isNaN(nativeDate.getTime())) {
37
+ return nativeDate;
38
+ }
39
+ const date = parse(normalizedDateStr, "yyyy-MM-dd", new Date());
25
40
  if (!isNaN(date.getTime()))
26
41
  return date;
27
42
  return undefined;
@@ -33,7 +48,51 @@ function parseDateString(dateStr) {
33
48
  function formatISODate(date) {
34
49
  return format(date, "yyyy-MM-dd");
35
50
  }
36
- const DateInput = React.forwardRef(({ label, value, onValueChange, description, error, invalid = false, hideLabel = false, placeholder = "Pick a date", disabled = false, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }, ref) => {
51
+ function formatDisplayDate(date) {
52
+ return format(date, "d MMM yyyy");
53
+ }
54
+ function getDateTime(date) {
55
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
56
+ }
57
+ function isDateOutsideBounds(date, minDate, maxDate) {
58
+ const dateTime = getDateTime(date);
59
+ if (minDate && dateTime < getDateTime(minDate))
60
+ return true;
61
+ if (maxDate && dateTime > getDateTime(maxDate))
62
+ return true;
63
+ return false;
64
+ }
65
+ function parseDateRangeValue(value) {
66
+ const from = parseDateString(value.from);
67
+ const to = parseDateString(value.to);
68
+ if (!from && !to)
69
+ return undefined;
70
+ return { from, to };
71
+ }
72
+ function formatDateRangeValue(range) {
73
+ if (!(range === null || range === void 0 ? void 0 : range.from) && !(range === null || range === void 0 ? void 0 : range.to)) {
74
+ return {};
75
+ }
76
+ return {
77
+ ...(range.from ? { from: formatISODate(range.from) } : {}),
78
+ ...(range.to ? { to: formatISODate(range.to) } : {}),
79
+ };
80
+ }
81
+ function formatDisplayRange(range) {
82
+ if ((range === null || range === void 0 ? void 0 : range.from) && range.to) {
83
+ return `${formatDisplayDate(range.from)} - ${formatDisplayDate(range.to)}`;
84
+ }
85
+ if (range === null || range === void 0 ? void 0 : range.from) {
86
+ return `${formatDisplayDate(range.from)} -`;
87
+ }
88
+ if (range === null || range === void 0 ? void 0 : range.to) {
89
+ return `- ${formatDisplayDate(range.to)}`;
90
+ }
91
+ return undefined;
92
+ }
93
+ const DateInput = React.forwardRef((props, ref) => {
94
+ var _a, _b, _c;
95
+ const { label, appearance = "field", description, error, invalid = false, hideLabel = false, disabled = false, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, } = props;
37
96
  const [open, setOpen] = React.useState(false);
38
97
  const generatedId = React.useId();
39
98
  const inputId = id !== null && id !== void 0 ? id : `date-input-${generatedId}`;
@@ -41,21 +100,35 @@ const DateInput = React.forwardRef(({ label, value, onValueChange, description,
41
100
  const showDescription = Boolean(description) && !error;
42
101
  const descriptionId = showDescription ? `${inputId}-description` : undefined;
43
102
  const isInvalid = invalid || Boolean(error);
44
- const selectedDate = React.useMemo(() => parseDateString(value), [value]);
45
- const displayValue = selectedDate
46
- ? format(selectedDate, "d MMM yyyy")
47
- : undefined;
103
+ const isRange = props.mode === "range";
104
+ const selectedDate = React.useMemo(() => (isRange ? undefined : parseDateString(props.value)), [isRange, props.value]);
105
+ const selectedRange = React.useMemo(() => (isRange ? parseDateRangeValue(props.value) : undefined), [isRange, props.value]);
106
+ const displayValue = isRange
107
+ ? formatDisplayRange(selectedRange)
108
+ : selectedDate
109
+ ? formatDisplayDate(selectedDate)
110
+ : undefined;
111
+ const placeholder = (_a = props.placeholder) !== null && _a !== void 0 ? _a : (isRange ? "Pick range" : "Pick a date");
48
112
  const handleSelect = (date) => {
49
- onValueChange(date ? formatISODate(date) : "");
113
+ if (props.mode === "range")
114
+ return;
115
+ props.onValueChange(date ? formatISODate(date) : "");
50
116
  setOpen(false);
51
117
  };
52
- return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: "relative w-full", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", style: { width: 14, height: 14 }, "aria-hidden": "true", children: [_jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", ry: "2" }), _jsx("line", { x1: "16", x2: "16", y1: "2", y2: "6" }), _jsx("line", { x1: "8", x2: "8", y1: "2", y2: "6" }), _jsx("line", { x1: "3", x2: "21", y1: "10", y2: "10" })] }), _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "cursor-pointer pl-9 text-left", !selectedDate && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: displayValue !== null && displayValue !== void 0 ? displayValue : _jsx("span", { children: placeholder }) })] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: (date) => {
53
- if (minDate && date < minDate)
54
- return true;
55
- if (maxDate && date > maxDate)
56
- return true;
57
- return false;
58
- }, defaultMonth: selectedDate, autoFocus: true }) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
118
+ const handleRangeSelect = (range) => {
119
+ if (props.mode !== "range")
120
+ return;
121
+ props.onValueChange(formatDateRangeValue(range));
122
+ if ((range === null || range === void 0 ? void 0 : range.from) && range.to) {
123
+ setOpen(false);
124
+ }
125
+ };
126
+ const disabledDays = (date) => isDateOutsideBounds(date, minDate, maxDate);
127
+ const calendarContent = (_jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: props.mode === "range" ? (_jsx(Calendar, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, defaultMonth: (_b = selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) !== null && _b !== void 0 ? _b : selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.to, numberOfMonths: (_c = props.numberOfMonths) !== null && _c !== void 0 ? _c : 2, autoFocus: true })) : (_jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: disabledDays, defaultMonth: selectedDate, autoFocus: true })) }));
128
+ if (appearance === "inline") {
129
+ return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsxs(PopoverRoot, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-primary underline decoration-primary/40 underline-offset-4 transition-colors hover:decoration-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", !displayValue && "text-muted-foreground decoration-border", isInvalid && "text-destructive decoration-destructive", triggerClassName), children: [_jsxs("span", { className: "sr-only", children: [label, ": "] }), _jsx("span", { children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder })] }) }), calendarContent] }), showDescription ? (_jsx("span", { id: descriptionId, className: "sr-only", children: description })) : null, error ? (_jsx("span", { id: errorId, role: "alert", className: "sr-only", children: error })) : null] }));
130
+ }
131
+ return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "relative cursor-pointer pr-9 text-left", !displayValue && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: [_jsx("span", { className: "block truncate", children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder }), _jsx(CalendarIcon, { "aria-hidden": "true", className: "pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground", strokeWidth: 2 })] }) }), calendarContent] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
59
132
  });
60
133
  DateInput.displayName = "DateInput";
61
134
  export { DateInput };
@@ -4,20 +4,21 @@ import * as React from "react";
4
4
  import * as DialogPrimitive from "@radix-ui/react-dialog";
5
5
  import { XIcon } from "./animated-icons/x";
6
6
  import { cn } from "./lib/utils";
7
+ import { typographyVariants } from "./typography";
7
8
  const DialogRoot = DialogPrimitive.Root;
8
9
  const DialogTrigger = DialogPrimitive.Trigger;
9
10
  const DialogPortal = DialogPrimitive.Portal;
10
11
  const DialogClose = DialogPrimitive.Close;
11
12
  const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
12
13
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
13
- const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
14
+ const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-3 border bg-background p-4 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-overlay", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-control text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
14
15
  DialogSurface.displayName = DialogPrimitive.Content.displayName;
15
16
  const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
16
17
  DialogHeader.displayName = "DialogHeader";
17
18
  const DialogFooter = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
18
19
  DialogFooter.displayName = "DialogFooter";
19
- const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Title, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
20
+ const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Title, { ref: ref, className: cn(typographyVariants({ variant: "subheading" }), className), ...props })));
20
21
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
21
- const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Description, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
22
+ const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Description, { ref: ref, className: cn(typographyVariants({ variant: "bodySm" }), "text-muted-foreground", className), ...props })));
22
23
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
23
24
  export { DialogRoot, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogSurface, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };
@@ -1,10 +1,17 @@
1
1
  import * as React from "react";
2
+ import { type BadgeProps } from "./badge";
2
3
  import { type TooltipProps } from "./tooltip";
4
+ export interface DraggableTabBadge {
5
+ label: React.ReactNode;
6
+ variant?: BadgeProps["variant"];
7
+ bordered?: BadgeProps["bordered"];
8
+ }
3
9
  export interface DraggableTabItem {
4
10
  id: string;
5
11
  label: React.ReactNode;
6
12
  active?: boolean;
7
13
  disabled?: boolean;
14
+ badge?: DraggableTabBadge;
8
15
  leading?: React.ReactNode;
9
16
  trailing?: React.ReactNode;
10
17
  tooltip?: React.ReactNode;
@@ -1,9 +1,10 @@
1
1
  "use client";
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core";
4
4
  import { SortableContext, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, } from "@dnd-kit/sortable";
5
5
  import { CSS } from "@dnd-kit/utilities";
6
6
  import { XIcon } from "./animated-icons/x";
7
+ import { Badge } from "./badge";
7
8
  import { cn } from "./lib/utils";
8
9
  import { Tooltip } from "./tooltip";
9
10
  function TabButton({ item, dragHandleProps, }) {
@@ -14,13 +15,13 @@ function TabButton({ item, dragHandleProps, }) {
14
15
  : item.active
15
16
  ? "text-foreground"
16
17
  : "text-muted-foreground hover:text-foreground";
17
- const content = (_jsxs("div", { className: cn("group flex items-center gap-2 rounded-t-md border-b-2 px-3 transition-colors select-none", item.disabled
18
+ const content = (_jsxs("div", { className: cn("group flex items-center gap-1.5 border-b-2 px-2.5 transition-colors select-none", item.disabled
18
19
  ? "cursor-not-allowed opacity-50"
19
20
  : isDraggable
20
21
  ? "cursor-grab active:cursor-grabbing"
21
22
  : "cursor-pointer", item.active
22
- ? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-green-500 hover:bg-muted"
23
- : (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-muted", item.className), ...dragHandleProps, children: [_jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-2 py-3 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
23
+ ? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-[hsl(var(--tab-indicator))] bg-transparent hover:bg-transparent"
24
+ : (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-[hsl(var(--tab-trigger-hover-background))]", item.className), ...dragHandleProps, children: [_jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-1.5 py-2 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.badge ? (_jsx(Badge, { variant: item.badge.variant, bordered: item.badge.bordered, size: "icon", children: item.badge.label })) : null, item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
24
25
  var _a;
25
26
  event.stopPropagation();
26
27
  (_a = item.onClose) === null || _a === void 0 ? void 0 : _a.call(item);
@@ -56,6 +57,6 @@ function DraggableTabs({ staticTabs = [], tabs, onReorder, className, ...props }
56
57
  onReorder(oldIndex, newIndex);
57
58
  }
58
59
  };
59
- return (_jsxs("div", { className: cn("flex items-end gap-1 border-b overflow-x-auto overflow-y-hidden bg-background", className), ...props, children: [staticTabs.map((tab) => (_jsx(TabButton, { item: tab }, tab.id))), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: tabs.map((tab) => tab.id), strategy: horizontalListSortingStrategy, children: tabs.map((tab) => (_jsx(SortableTab, { item: tab }, tab.id))) }) })] }));
60
+ return (_jsxs("div", { "data-slot": "draggable-tabs", className: cn("flex items-end gap-1 border-b overflow-x-auto overflow-y-hidden bg-transparent", "border-[hsl(var(--layout-surface-border))]", className), ...props, children: [staticTabs.map((tab) => (_jsx(TabButton, { item: tab }, tab.id))), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: tabs.map((tab) => tab.id), strategy: horizontalListSortingStrategy, children: tabs.map((tab) => (_jsx(SortableTab, { item: tab }, tab.id))) }) })] }));
60
61
  }
61
62
  export { DraggableTabs };
package/dist/drawer.js CHANGED
@@ -34,7 +34,7 @@ function renderDrawerAction({ action, close, defaultVariant, }) {
34
34
  }
35
35
  }, children: label }));
36
36
  }
37
- const drawerSurfaceVariants = cva("fixed z-50 flex flex-col gap-4 overflow-y-auto bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", {
37
+ const drawerSurfaceVariants = cva("fixed z-50 flex flex-col gap-3 overflow-y-auto bg-background p-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", {
38
38
  variants: {
39
39
  side: {
40
40
  left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-lg",
@@ -46,7 +46,7 @@ const drawerSurfaceVariants = cva("fixed z-50 flex flex-col gap-4 overflow-y-aut
46
46
  },
47
47
  });
48
48
  function DrawerSurface({ side, className, children, hideCloseButton, ...props }) {
49
- return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] }));
49
+ return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-control text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] }));
50
50
  }
51
51
  function Drawer({ open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, side = "right", contentClassName, bodyClassName, hideCloseButton, }) {
52
52
  const [isOpen, setIsOpen] = useControllableOpen({
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+ import { type ButtonProps } from "./button";
3
+ import { type PopoverProps } from "./popover";
4
+ type DropdownButtonPopoverProps = Pick<PopoverProps, "align" | "alignOffset" | "avoidCollisions" | "collisionPadding" | "defaultOpen" | "hideWhenDetached" | "modal" | "onOpenChange" | "open" | "side" | "sideOffset" | "sticky">;
5
+ export interface DropdownButtonProps extends Omit<ButtonProps, "children">, DropdownButtonPopoverProps {
6
+ label: React.ReactNode;
7
+ leadingIcon?: React.ReactNode;
8
+ children: React.ReactNode;
9
+ contentClassName?: string;
10
+ dropdownAriaLabel?: string;
11
+ menuWidth?: "trigger" | "content";
12
+ /**
13
+ * Renders separate primary and menu triggers. Set `false` to keep one popover trigger even when `onClick` is provided.
14
+ */
15
+ split?: boolean;
16
+ }
17
+ declare function DropdownButton({ label, leadingIcon, children, className, contentClassName, dropdownAriaLabel, menuWidth, align, alignOffset, avoidCollisions, collisionPadding, defaultOpen, disabled, hideWhenDetached, loading, loadingIndicator, loadingText, modal, onClick, onOpenChange, open, side, sideOffset, split: splitProp, sticky, type, variant, size, ...buttonProps }: DropdownButtonProps): import("react/jsx-runtime").JSX.Element;
18
+ export { DropdownButton };
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDownIcon } from "./animated-icons";
4
+ import { Button } from "./button";
5
+ import { Popover } from "./popover";
6
+ import { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger, } from "./popover-primitive";
7
+ import { cn } from "./lib/utils";
8
+ const splitButtonDividerClassNames = {
9
+ default: "before:bg-primary-foreground/30",
10
+ destructive: "before:bg-destructive-foreground/30",
11
+ outline: "before:bg-[hsl(var(--button-outline-border))]",
12
+ secondary: "before:bg-secondary-foreground/20",
13
+ ghost: "before:bg-border",
14
+ link: "before:bg-primary/25",
15
+ };
16
+ function DropdownButton({ label, leadingIcon, children, className, contentClassName, dropdownAriaLabel, menuWidth = "trigger", align = "end", alignOffset, avoidCollisions, collisionPadding, defaultOpen, disabled, hideWhenDetached, loading, loadingIndicator, loadingText, modal, onClick, onOpenChange, open, side, sideOffset = 4, split: splitProp, sticky, type = "button", variant, size, ...buttonProps }) {
17
+ const menuContentClassName = cn("shadow-overlay-strong border-border/80 bg-popover ring-1 ring-border/50", menuWidth === "trigger" &&
18
+ "w-[var(--radix-popover-trigger-width)] min-w-56", contentClassName);
19
+ const labelContent = (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [leadingIcon ? (_jsx("span", { className: "inline-flex shrink-0 items-center", children: leadingIcon })) : null, _jsx("span", { className: "truncate", children: label })] }));
20
+ const menuButtonLabel = dropdownAriaLabel !== null && dropdownAriaLabel !== void 0 ? dropdownAriaLabel : (typeof label === "string" ? `${label} menu` : "Open menu");
21
+ const menuButtonSizeClassName = size === "sm" || size === "compact" || size === "compactIcon"
22
+ ? "w-8"
23
+ : "w-control";
24
+ const resolvedVariant = variant !== null && variant !== void 0 ? variant : "default";
25
+ const split = splitProp !== null && splitProp !== void 0 ? splitProp : Boolean(onClick);
26
+ if (split) {
27
+ return (_jsxs(PopoverRoot, { defaultOpen: defaultOpen, modal: modal, onOpenChange: onOpenChange, open: open, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsxs("div", { className: cn("inline-flex items-stretch", className), children: [_jsx(Button, { type: type, variant: variant, size: size, className: cn("min-w-0 flex-1 justify-start rounded-r-none", variant === "outline" && "border-r-0"), disabled: disabled, loading: loading, loadingIndicator: loadingIndicator, loadingText: loadingText, onClick: onClick, ...buttonProps, children: labelContent }), _jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: variant, size: size, "aria-label": menuButtonLabel, className: cn("relative shrink-0 rounded-l-none px-0 before:absolute before:inset-y-0 before:left-0 before:w-px before:content-['']", menuButtonSizeClassName, splitButtonDividerClassNames[resolvedVariant], variant === "outline" && "border-l-0"), disabled: disabled || loading, children: _jsx(ChevronDownIcon, { size: 14 }) }) })] }) }), _jsx(PopoverContent, { align: align, alignOffset: alignOffset, avoidCollisions: avoidCollisions, collisionPadding: collisionPadding, hideWhenDetached: hideWhenDetached, side: side, sideOffset: sideOffset, sticky: sticky, className: cn("overflow-hidden p-1", menuContentClassName), children: children })] }));
28
+ }
29
+ return (_jsx(Popover, { surface: "menu", align: align, alignOffset: alignOffset, avoidCollisions: avoidCollisions, collisionPadding: collisionPadding, defaultOpen: defaultOpen, hideWhenDetached: hideWhenDetached, modal: modal, onOpenChange: onOpenChange, open: open, side: side, sideOffset: sideOffset, sticky: sticky, contentClassName: menuContentClassName, trigger: _jsxs(Button, { type: type, variant: variant, size: size, className: cn("justify-between", className), disabled: disabled, loading: loading, loadingIndicator: loadingIndicator, loadingText: loadingText, onClick: onClick, ...buttonProps, children: [labelContent, _jsx(ChevronDownIcon, { className: "ml-auto", size: 14 })] }), children: children }));
30
+ }
31
+ export { DropdownButton };
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import { type ButtonProps } from "./button";
3
+ export interface EditButtonProps extends Omit<ButtonProps, "children" | "size" | "variant"> {
4
+ label?: React.ReactNode;
5
+ targetLabel?: string;
6
+ size?: Extract<ButtonProps["size"], "sm" | "compact" | "default">;
7
+ variant?: Extract<ButtonProps["variant"], "outline" | "ghost" | "secondary">;
8
+ }
9
+ declare function EditButton({ label, targetLabel, size, variant, "aria-label": ariaLabel, ...props }: EditButtonProps): import("react/jsx-runtime").JSX.Element;
10
+ export { EditButton };
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PencilIcon } from "./animated-icons";
3
+ import { Button } from "./button";
4
+ function EditButton({ label = "Edit", targetLabel, size = "compact", variant = "outline", "aria-label": ariaLabel, ...props }) {
5
+ return (_jsxs(Button, { variant: variant, size: size, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (targetLabel ? `Edit ${targetLabel}` : undefined), ...props, children: [_jsx(PencilIcon, { size: 14 }), label] }));
6
+ }
7
+ export { EditButton };
@@ -23,10 +23,12 @@ export interface EditableTableProps {
23
23
  className?: string;
24
24
  emptyPlaceholder?: string;
25
25
  checkable?: boolean;
26
+ checkableHeader?: React.ReactNode;
26
27
  activeField?: string;
28
+ addRowLabel?: React.ReactNode;
27
29
  renderRowActions?: (context: EditableTableRowActionContext) => React.ReactNode;
28
30
  }
29
- declare function EditableTable({ value, onChange, columns, isEditing, className, emptyPlaceholder, checkable, activeField, renderRowActions, }: EditableTableProps): import("react/jsx-runtime").JSX.Element;
31
+ declare function EditableTable({ value, onChange, columns, isEditing, className, emptyPlaceholder, checkable, checkableHeader, activeField, addRowLabel, renderRowActions, }: EditableTableProps): import("react/jsx-runtime").JSX.Element;
30
32
  declare namespace EditableTable {
31
33
  var displayName: string;
32
34
  }
@@ -4,6 +4,7 @@ import { Button } from "./button";
4
4
  import { PlusIcon } from "./animated-icons/plus";
5
5
  import { TrashIcon } from "./animated-icons/trash";
6
6
  import { Checkbox } from "./checkbox";
7
+ import { EmptyState } from "./empty-state";
7
8
  import { InputControl } from "./input-control";
8
9
  import { TableRoot as Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "./table";
9
10
  import { cn } from "./lib/utils";
@@ -32,7 +33,7 @@ function setNestedValue(obj, path, value) {
32
33
  current[parts[parts.length - 1]] = value;
33
34
  return result;
34
35
  }
35
- function EditableTable({ value, onChange, columns, isEditing = false, className, emptyPlaceholder = "-", checkable = false, activeField = "active", renderRowActions, }) {
36
+ function EditableTable({ value, onChange, columns, isEditing = false, className, emptyPlaceholder = "Enter text...", checkable = false, checkableHeader, activeField = "active", addRowLabel = "Add Row", renderRowActions, }) {
36
37
  const [editingCell, setEditingCell] = React.useState(null);
37
38
  const [editValue, setEditValue] = React.useState("");
38
39
  const inputRef = React.useRef(null);
@@ -48,8 +49,12 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
48
49
  if (!isEditing) {
49
50
  return;
50
51
  }
52
+ if ((editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
53
+ (editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === colPath) {
54
+ return;
55
+ }
51
56
  const cellValue = getNestedValue(value[rowIndex], colPath);
52
- setEditValue(cellValue !== undefined && cellValue !== null ? String(cellValue) : "");
57
+ setEditValue(isEmptyCellValue(cellValue) ? "" : String(cellValue));
53
58
  setEditingCell({ rowIndex, colPath });
54
59
  };
55
60
  const commitEdit = () => {
@@ -102,27 +107,35 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
102
107
  };
103
108
  onChange(nextRows);
104
109
  }, [activeField, onChange, value]);
110
+ const isEmptyCellValue = (cellValue) => cellValue === null ||
111
+ cellValue === undefined ||
112
+ cellValue === "" ||
113
+ (typeof cellValue === "string" && cellValue.trim() === "-");
105
114
  const formatCellValue = (cellValue) => {
106
- if (cellValue === null || cellValue === undefined || cellValue === "") {
107
- return emptyPlaceholder;
115
+ if (isEmptyCellValue(cellValue)) {
116
+ return "";
108
117
  }
109
118
  return String(cellValue);
110
119
  };
111
120
  const hasActionsColumn = isEditing || Boolean(renderRowActions);
112
- return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "rounded-md border overflow-x-auto", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [checkable ? _jsx(TableHead, { width: "48px", minWidth: "48px" }) : null, columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length +
121
+ const checkableColumnWidth = checkableHeader ? "9rem" : "48px";
122
+ return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "overflow-x-auto rounded-surface border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [checkable ? (_jsx(TableHead, { width: checkableColumnWidth, minWidth: checkableColumnWidth, children: checkableHeader })) : null, columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length +
113
123
  (checkable ? 1 : 0) +
114
- (hasActionsColumn ? 1 : 0), className: "py-8 text-center text-muted-foreground", children: "No data available" }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0 ? "bg-muted/30" : undefined, children: [checkable ? (_jsx(TableCell, { width: "48px", minWidth: "48px", children: _jsx("div", { onClick: (event) => event.stopPropagation(), children: _jsx(Checkbox, { checked: Boolean(row[activeField]), disabled: !isEditing, onChange: isEditing
124
+ (hasActionsColumn ? 1 : 0), className: "p-0", children: _jsx(EmptyState, { message: "No data available", description: "There are no rows to display in this table yet.", className: "border-0 bg-transparent px-0 py-[var(--space-6)]" }) }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0
125
+ ? "bg-[hsl(var(--table-row-striped-background))]"
126
+ : undefined, children: [checkable ? (_jsx(TableCell, { width: checkableColumnWidth, minWidth: checkableColumnWidth, children: _jsx("div", { className: "flex items-center", onClick: (event) => event.stopPropagation(), children: _jsx(Checkbox, { checked: Boolean(row[activeField]), disabled: !isEditing, onChange: isEditing
115
127
  ? (event) => handleToggleRow(rowIndex, event.currentTarget.checked)
116
128
  : undefined }) }) })) : null, columns.map((column, columnIndex) => {
117
129
  const cellValue = getNestedValue(row, column.path);
130
+ const isEmptyCell = isEmptyCellValue(cellValue);
118
131
  const isEditingCell = (editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
119
132
  (editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === column.path;
120
- return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), width: column.width, minWidth: getColumnMinWidth(column), maxWidth: getColumnMaxWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-control w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
121
- cellValue === undefined ||
122
- cellValue === ""
133
+ return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), width: column.width, minWidth: getColumnMinWidth(column), maxWidth: getColumnMaxWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx("div", { className: "flex min-h-8 items-center", children: _jsx(InputControl, { ref: inputRef, value: editValue, placeholder: emptyPlaceholder, onChange: (event) => setEditValue(event.target.value), onClick: (event) => event.stopPropagation(), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-8 w-full px-2 py-1 text-sm" }) })) : (_jsx("span", { className: cn("flex min-h-8 items-center whitespace-normal break-words", isEmptyCell
123
134
  ? "text-muted-foreground"
124
- : undefined), style: { maxWidth: getColumnMaxWidth(column) }, children: formatCellValue(cellValue) })) }, `cell-${rowIndex}-${columnIndex}`));
125
- }), hasActionsColumn ? (_jsx(TableCell, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px", children: _jsxs("div", { className: "flex items-center justify-end gap-1", children: [renderRowActions
135
+ : undefined), style: { maxWidth: getColumnMaxWidth(column) }, children: isEmptyCell && isEditing
136
+ ? emptyPlaceholder
137
+ : formatCellValue(cellValue) })) }, `cell-${rowIndex}-${columnIndex}`));
138
+ }), hasActionsColumn ? (_jsx(TableCell, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px", children: _jsxs("div", { className: "flex min-h-8 items-center justify-end gap-1", children: [renderRowActions
126
139
  ? renderRowActions({
127
140
  row,
128
141
  rowIndex,
@@ -132,7 +145,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
132
145
  insertRow: (nextRow, index = rowIndex + 1) => handleInsertRow(nextRow, index),
133
146
  removeRow: () => handleDeleteRow(rowIndex),
134
147
  })
135
- : null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "text-destructive hover:bg-destructive/10 hover:text-destructive", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsxs(Button, { type: "button", variant: "outline", onClick: handleAddRow, className: "w-full justify-center", children: [_jsx(PlusIcon, { size: 16 }), "Add Row"] })) : null] }));
148
+ : null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:text-destructive", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsxs(Button, { type: "button", variant: "outline", onClick: handleAddRow, className: "w-full justify-center", children: [_jsx(PlusIcon, { size: 16 }), addRowLabel] })) : null] }));
136
149
  }
137
150
  EditableTable.displayName = "EditableTable";
138
151
  export { EditableTable };
package/dist/field.d.ts CHANGED
@@ -4,6 +4,10 @@ interface FieldLabelProps extends React.ComponentProps<"label"> {
4
4
  required?: boolean;
5
5
  }
6
6
  declare function FieldLabel({ className, required, children, ...props }: FieldLabelProps): import("react/jsx-runtime").JSX.Element;
7
- declare function FieldDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
8
- declare function FieldError({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element | null;
9
- export { Field, FieldDescription, FieldError, FieldLabel };
7
+ interface FieldLegendProps extends React.ComponentProps<"legend"> {
8
+ required?: boolean;
9
+ }
10
+ declare function FieldLegend({ className, required, children, ...props }: FieldLegendProps): import("react/jsx-runtime").JSX.Element;
11
+ declare function FieldDescription({ className, ...props }: Omit<React.ComponentProps<"p">, "color">): import("react/jsx-runtime").JSX.Element;
12
+ declare function FieldError({ className, ...props }: Omit<React.ComponentProps<"p">, "color">): import("react/jsx-runtime").JSX.Element | null;
13
+ export { Field, FieldDescription, FieldError, FieldLabel, FieldLegend };
package/dist/field.js CHANGED
@@ -1,18 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "./lib/utils";
3
+ import { Typography } from "./typography";
3
4
  function Field({ className, ...props }) {
4
5
  return (_jsx("div", { "data-slot": "field", className: cn("group/field flex w-full flex-col gap-2", className), ...props }));
5
6
  }
6
7
  function FieldLabel({ className, required, children, ...props }) {
7
- return (_jsxs("label", { "data-slot": "field-label", className: cn("text-sm font-medium leading-none group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:opacity-50 group-data-[invalid=true]/field:text-destructive", className), ...props, children: [children, required ? (_jsx("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })) : null] }));
8
+ return (_jsx(Typography, { asChild: true, variant: "label", className: cn("group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:opacity-50 group-data-[invalid=true]/field:text-destructive", className), children: _jsxs("label", { "data-slot": "field-label", ...props, children: [children, required ? (_jsx("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })) : null] }) }));
9
+ }
10
+ function FieldLegend({ className, required, children, ...props }) {
11
+ return (_jsx(Typography, { asChild: true, variant: "label", className: cn("group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:opacity-50 group-data-[invalid=true]/field:text-destructive", className), children: _jsxs("legend", { "data-slot": "field-legend", ...props, children: [children, required ? (_jsx("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })) : null] }) }));
8
12
  }
9
13
  function FieldDescription({ className, ...props }) {
10
- return (_jsx("p", { "data-slot": "field-description", className: cn("text-sm leading-normal text-muted-foreground", className), ...props }));
14
+ return (_jsx(Typography, { as: "p", variant: "bodySm", color: "muted", "data-slot": "field-description", className: className, ...props }));
11
15
  }
12
16
  function FieldError({ className, ...props }) {
13
17
  if (!props.children) {
14
18
  return null;
15
19
  }
16
- return (_jsx("p", { role: "alert", "data-slot": "field-error", className: cn("text-sm leading-normal text-destructive", className), ...props }));
20
+ return (_jsx(Typography, { as: "p", variant: "bodySm", role: "alert", "data-slot": "field-error", className: cn("text-destructive", className), ...props }));
17
21
  }
18
- export { Field, FieldDescription, FieldError, FieldLabel };
22
+ export { Field, FieldDescription, FieldError, FieldLabel, FieldLegend };
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import type { FileUploadProgress, FileUploadResult, FileUploadStatus } from "./use-file-upload";
3
+ export interface FileUploadStatusToastFile {
4
+ name: string;
5
+ size?: number | string;
6
+ type?: string;
7
+ progress?: number;
8
+ status?: FileUploadStatus;
9
+ error?: string;
10
+ result?: FileUploadResult;
11
+ }
12
+ export interface FileUploadStatusToastProps {
13
+ files: FileUploadStatusToastFile[];
14
+ uploadProgress?: Map<string, FileUploadProgress> | FileUploadProgress[];
15
+ title?: React.ReactNode;
16
+ description?: React.ReactNode;
17
+ className?: string;
18
+ onCancel?: (file: FileUploadStatusToastFile) => void;
19
+ onRemove?: (file: FileUploadStatusToastFile) => void;
20
+ onDismiss?: () => void;
21
+ }
22
+ export interface ShowFileUploadStatusToastOptions extends FileUploadStatusToastProps {
23
+ id?: string | number;
24
+ duration?: number;
25
+ dismissible?: boolean;
26
+ }
27
+ export declare function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, onDismiss, }: FileUploadStatusToastProps): import("react/jsx-runtime").JSX.Element;
28
+ export declare function showFileUploadStatusToast({ id, duration, dismissible, onDismiss, ...props }: ShowFileUploadStatusToastOptions): string | number;