@getgreenline/blaze-ui 1.0.24 → 1.0.26

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 (35) hide show
  1. package/dist/components/alert-dialog.d.ts +4 -1
  2. package/dist/components/alert-dialog.d.ts.map +1 -1
  3. package/dist/components/alert-dialog.js +3 -2
  4. package/dist/components/button.d.ts.map +1 -1
  5. package/dist/components/button.js +1 -1
  6. package/dist/components/data-table.d.ts.map +1 -1
  7. package/dist/components/data-table.js +100 -31
  8. package/dist/components/login-screen.d.ts +4 -0
  9. package/dist/components/login-screen.d.ts.map +1 -0
  10. package/dist/components/login-screen.js +299 -0
  11. package/dist/components/login-screen.types.d.ts +82 -0
  12. package/dist/components/login-screen.types.d.ts.map +1 -0
  13. package/dist/components/login-screen.views.d.ts +114 -0
  14. package/dist/components/login-screen.views.d.ts.map +1 -0
  15. package/dist/components/login-screen.views.js +53 -0
  16. package/dist/components/search-bar.d.ts +15 -0
  17. package/dist/components/search-bar.d.ts.map +1 -0
  18. package/dist/components/search-bar.js +25 -0
  19. package/dist/components/selection-panel.d.ts +29 -0
  20. package/dist/components/selection-panel.d.ts.map +1 -0
  21. package/dist/components/selection-panel.js +166 -0
  22. package/dist/components/sheet.d.ts +2 -1
  23. package/dist/components/sheet.d.ts.map +1 -1
  24. package/dist/components/sheet.js +5 -4
  25. package/dist/components/visually-hidden.d.ts +16 -0
  26. package/dist/components/visually-hidden.d.ts.map +1 -0
  27. package/dist/components/visually-hidden.js +22 -0
  28. package/dist/globals.css +295 -68
  29. package/dist/index.d.ts +5 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +5 -0
  32. package/dist/lib/portal-wrapper.d.ts +32 -0
  33. package/dist/lib/portal-wrapper.d.ts.map +1 -0
  34. package/dist/lib/portal-wrapper.js +34 -0
  35. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ import { type DataTableColumn, type DataTableRow } from "./data-table";
2
+ export interface SelectionPanelProps<T extends DataTableRow> {
3
+ open: boolean;
4
+ onClose: () => void;
5
+ onDone: (selectedIds: string[]) => void;
6
+ title?: string;
7
+ description?: string;
8
+ availableItems: T[];
9
+ columns: DataTableColumn<T>[];
10
+ selectedColumns?: DataTableColumn<T>[];
11
+ selectedIds: string[];
12
+ loading?: boolean;
13
+ treeMode?: boolean;
14
+ availableLabel?: string;
15
+ selectedLabel?: string;
16
+ addButtonLabel?: string;
17
+ removeButtonLabel?: string;
18
+ doneButtonLabel?: string;
19
+ cancelButtonLabel?: string;
20
+ availableEmptyMessage?: string;
21
+ selectedEmptyMessage?: string;
22
+ width?: string;
23
+ maxWidth?: string;
24
+ showConfirmOnClose?: boolean;
25
+ confirmCloseMessage?: string;
26
+ onBeforeSelectionChange?: (selectedIds: string[]) => string[];
27
+ }
28
+ export declare function SelectionPanel<T extends DataTableRow>({ open, onClose, onDone, title, description, availableItems, columns, selectedColumns, selectedIds: initialSelectedIds, loading, treeMode, availableLabel, selectedLabel, addButtonLabel, removeButtonLabel, doneButtonLabel, cancelButtonLabel, availableEmptyMessage, selectedEmptyMessage, width, maxWidth, showConfirmOnClose, confirmCloseMessage, onBeforeSelectionChange, }: SelectionPanelProps<T>): import("react/jsx-runtime").JSX.Element;
29
+ //# sourceMappingURL=selection-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection-panel.d.ts","sourceRoot":"","sources":["../../src/components/selection-panel.tsx"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAA;AAuBrB,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,YAAY;IACzD,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,CAAC,EAAE,CAAA;IACnB,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAA;IACtC,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,uBAAuB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,CAAA;CAC9D;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,YAAY,EAAE,EACrD,IAAI,EACJ,OAAO,EACP,MAAM,EACN,KAAsB,EACtB,WAAW,EACX,cAAc,EACd,OAAO,EACP,eAAe,EACf,WAAW,EAAE,kBAAkB,EAC/B,OAAe,EACf,QAAgB,EAChB,cAA4B,EAC5B,aAA0B,EAC1B,cAA+B,EAC/B,iBAAqC,EACrC,eAAwB,EACxB,iBAA4B,EAC5B,qBAAqB,EACrB,oBAA0C,EAC1C,KAAa,EACb,QAAmB,EACnB,kBAAyB,EACzB,mBAAkF,EAClF,uBAAuB,GACxB,EAAE,mBAAmB,CAAC,CAAC,CAAC,2CA6VxB"}
@@ -0,0 +1,166 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { cn } from '../lib/utils.js';
4
+ import { SearchBar } from './search-bar.js';
5
+ import { DataTable } from './data-table.js';
6
+ import { Button } from './button.js';
7
+ import { Sheet, SheetContent, SheetTitle, SheetFooter } from './sheet.js';
8
+ import { VisuallyHidden } from './visually-hidden.js';
9
+ import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from './alert-dialog.js';
10
+
11
+ function SelectionPanel({ open, onClose, onDone, title = "Select Items", description, availableItems, columns, selectedColumns, selectedIds: initialSelectedIds, loading = false, treeMode = false, availableLabel = "Available", selectedLabel = "Selected", addButtonLabel = "Add Selected", removeButtonLabel = "Remove Selected", doneButtonLabel = "Done", cancelButtonLabel = "Cancel", availableEmptyMessage, selectedEmptyMessage = "No items selected", width = "75%", maxWidth = "1400px", showConfirmOnClose = true, confirmCloseMessage = "Are you sure you want to exit without saving your changes?", onBeforeSelectionChange, }) {
12
+ const [selectedIds, setSelectedIds] = React.useState(new Set(initialSelectedIds));
13
+ const [availableChecked, setAvailableChecked] = React.useState(new Set());
14
+ const [selectedChecked, setSelectedChecked] = React.useState(new Set());
15
+ const [availableSearch, setAvailableSearch] = React.useState("");
16
+ const [selectedSearch, setSelectedSearch] = React.useState("");
17
+ const [availableSearchApplied, setAvailableSearchApplied] = React.useState("");
18
+ const [selectedSearchApplied, setSelectedSearchApplied] = React.useState("");
19
+ const [isDirty, setIsDirty] = React.useState(false);
20
+ const [showConfirmDialog, setShowConfirmDialog] = React.useState(false);
21
+ const availableHeadingId = React.useId();
22
+ const selectedHeadingId = React.useId();
23
+ React.useEffect(() => {
24
+ if (open) {
25
+ setSelectedIds(new Set(initialSelectedIds));
26
+ setAvailableChecked(new Set());
27
+ setSelectedChecked(new Set());
28
+ setAvailableSearch("");
29
+ setSelectedSearch("");
30
+ setAvailableSearchApplied("");
31
+ setSelectedSearchApplied("");
32
+ setIsDirty(false);
33
+ }
34
+ }, [open, initialSelectedIds]);
35
+ const availableItemsFiltered = React.useMemo(() => {
36
+ const filterRecursive = (items) => {
37
+ return items
38
+ .filter((item) => !selectedIds.has(item.id))
39
+ .map((item) => {
40
+ if (treeMode && item.children) {
41
+ return {
42
+ ...item,
43
+ children: filterRecursive(item.children),
44
+ };
45
+ }
46
+ return item;
47
+ });
48
+ };
49
+ let filtered = filterRecursive(availableItems);
50
+ if (availableSearchApplied) {
51
+ const searchLower = availableSearchApplied.toLowerCase();
52
+ const searchRecursive = (items) => {
53
+ return items.filter((item) => {
54
+ const matches = columns.some((col) => {
55
+ const value = item[col.key];
56
+ return String(value).toLowerCase().includes(searchLower);
57
+ });
58
+ if (treeMode && item.children) {
59
+ const matchingChildren = searchRecursive(item.children);
60
+ if (matchingChildren.length > 0) {
61
+ return true;
62
+ }
63
+ }
64
+ return matches;
65
+ });
66
+ };
67
+ filtered = searchRecursive(filtered);
68
+ }
69
+ return filtered;
70
+ }, [availableItems, selectedIds, availableSearchApplied, columns, treeMode]);
71
+ const selectedItemsData = React.useMemo(() => {
72
+ const findItemsById = (items, ids) => {
73
+ const result = [];
74
+ for (const item of items) {
75
+ if (ids.has(item.id)) {
76
+ result.push(item);
77
+ }
78
+ if (treeMode && item.children) {
79
+ result.push(...findItemsById(item.children, ids));
80
+ }
81
+ }
82
+ return result;
83
+ };
84
+ let selected = findItemsById(availableItems, selectedIds);
85
+ if (selectedSearchApplied) {
86
+ const searchLower = selectedSearchApplied.toLowerCase();
87
+ selected = selected.filter((item) => {
88
+ return columns.some((col) => {
89
+ const value = item[col.key];
90
+ return String(value).toLowerCase().includes(searchLower);
91
+ });
92
+ });
93
+ }
94
+ return selected;
95
+ }, [availableItems, selectedIds, selectedSearchApplied, columns, treeMode]);
96
+ const handleAvailableSelectionChange = React.useCallback((ids) => {
97
+ const transformedIds = onBeforeSelectionChange
98
+ ? onBeforeSelectionChange(ids)
99
+ : ids;
100
+ setAvailableChecked(new Set(transformedIds));
101
+ }, [onBeforeSelectionChange]);
102
+ const handleSelectedSelectionChange = React.useCallback((ids) => {
103
+ setSelectedChecked(new Set(ids));
104
+ }, []);
105
+ const handleAddSelected = React.useCallback(() => {
106
+ if (availableChecked.size === 0)
107
+ return;
108
+ setSelectedIds((prev) => {
109
+ const next = new Set(prev);
110
+ availableChecked.forEach((id) => next.add(id));
111
+ return next;
112
+ });
113
+ setAvailableChecked(new Set());
114
+ setIsDirty(true);
115
+ }, [availableChecked]);
116
+ const handleRemoveSelected = React.useCallback(() => {
117
+ if (selectedChecked.size === 0)
118
+ return;
119
+ setSelectedIds((prev) => {
120
+ const next = new Set(prev);
121
+ selectedChecked.forEach((id) => next.delete(id));
122
+ return next;
123
+ });
124
+ setSelectedChecked(new Set());
125
+ setIsDirty(true);
126
+ }, [selectedChecked]);
127
+ const handleDone = React.useCallback(() => {
128
+ onDone(Array.from(selectedIds));
129
+ onClose();
130
+ }, [selectedIds, onDone, onClose]);
131
+ const handleClose = React.useCallback(() => {
132
+ if (isDirty && showConfirmOnClose) {
133
+ setShowConfirmDialog(true);
134
+ }
135
+ else {
136
+ onClose();
137
+ }
138
+ }, [isDirty, showConfirmOnClose, onClose]);
139
+ const handleConfirmClose = React.useCallback(() => {
140
+ setShowConfirmDialog(false);
141
+ onClose();
142
+ }, [onClose]);
143
+ return (jsxs(Fragment, { children: [jsx(Sheet, { open: open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: jsxs(SheetContent, { side: "right", className: cn("tw:!p-0 tw:!z-[1200]"), overlayClassName: "tw:!z-[1200]", style: { width, maxWidth }, children: [jsx(VisuallyHidden, { children: jsx(SheetTitle, { children: title }) }), jsxs("div", { className: "tw:!flex tw:!h-full tw:!flex-col", children: [jsxs("div", { className: "tw:!flex tw:!flex-1 tw:!overflow-hidden", children: [jsxs("div", { className: "tw:!flex tw:!w-1/2 tw:!flex-col tw:!border-r", role: "region", "aria-labelledby": availableHeadingId, children: [jsxs("div", { className: "tw:!border-b tw:!p-4", children: [jsx("h2", { id: availableHeadingId, className: "tw:text-lg tw:!font-semibold tw:!mb-3", children: availableLabel }), jsx(SearchBar, { value: availableSearch, onChange: setAvailableSearch, onSearch: (term) => setAvailableSearchApplied(term), onClear: () => {
144
+ setAvailableSearch("");
145
+ setAvailableSearchApplied("");
146
+ }, placeholder: `Search ${availableLabel.toLowerCase()}...`, inputAriaLabel: `Search within ${availableLabel}` }), jsx("div", { className: "tw:!flex tw:!justify-end tw:!mt-3", children: jsx(Button, { size: "sm", onClick: handleAddSelected, disabled: availableChecked.size === 0, "aria-label": availableChecked.size === 0
147
+ ? addButtonLabel
148
+ : `${addButtonLabel} (${availableChecked.size} selected)`, children: addButtonLabel }) })] }), jsx("div", { className: "tw:!flex-1 tw:!overflow-hidden", children: jsx(DataTable, { columns: columns, data: availableItemsFiltered, onSelectionChange: handleAvailableSelectionChange, selectedRowIds: Array.from(availableChecked), treeData: treeMode, loading: loading, className: "tw:!h-full", emptyState: {
149
+ title: availableEmptyMessage || "No items available",
150
+ description: availableSearchApplied
151
+ ? "Try adjusting your search"
152
+ : undefined,
153
+ } }) }), jsxs("div", { className: "tw:!p-2 tw:text-sm tw:!text-muted-foreground", "aria-live": "polite", role: "status", children: [availableChecked.size, " Selected"] })] }), jsxs("div", { className: "tw:!flex tw:!w-1/2 tw:!flex-col", role: "region", "aria-labelledby": selectedHeadingId, children: [jsxs("div", { className: "tw:!border-b tw:!p-4", children: [jsx("h2", { id: selectedHeadingId, className: "tw:text-lg tw:!font-semibold tw:!mb-3", children: selectedLabel }), jsx(SearchBar, { value: selectedSearch, onChange: setSelectedSearch, onSearch: (term) => setSelectedSearchApplied(term), onClear: () => {
154
+ setSelectedSearch("");
155
+ setSelectedSearchApplied("");
156
+ }, placeholder: `Search ${selectedLabel.toLowerCase()}...`, inputAriaLabel: `Search within ${selectedLabel}` }), jsx("div", { className: "tw:!flex tw:!justify-end tw:!mt-3", children: jsx(Button, { size: "sm", onClick: handleRemoveSelected, disabled: selectedChecked.size === 0, variant: "destructive", "aria-label": selectedChecked.size === 0
157
+ ? removeButtonLabel
158
+ : `${removeButtonLabel} (${selectedChecked.size} selected)`, children: removeButtonLabel }) })] }), jsx("div", { className: "tw:!flex-1 tw:!overflow-hidden", children: jsx(DataTable, { columns: selectedColumns ?? columns, data: selectedItemsData, onSelectionChange: handleSelectedSelectionChange, selectedRowIds: Array.from(selectedChecked), treeData: false, className: "tw:!h-full", emptyState: {
159
+ title: selectedEmptyMessage,
160
+ description: selectedSearchApplied
161
+ ? "Try adjusting your search"
162
+ : undefined,
163
+ } }) }), jsxs("div", { className: "tw:!p-2 tw:text-sm tw:!text-muted-foreground", "aria-live": "polite", role: "status", children: [selectedIds.size, " Selected"] })] })] }), jsxs(SheetFooter, { className: "tw:!border-t tw:!flex tw:!flex-row tw:!justify-between tw:!items-center", children: [jsx(Button, { variant: "link", className: "tw:!text-primary tw:!px-0", onClick: handleClose, children: cancelButtonLabel }), jsx(Button, { onClick: handleDone, disabled: selectedIds.size === 0, children: doneButtonLabel })] })] })] }) }), jsx(AlertDialog, { open: showConfirmDialog, onOpenChange: setShowConfirmDialog, children: jsxs(AlertDialogContent, { className: "tw:!z-[1300]", overlayClassName: "tw:!z-[1300]", children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: "Unsaved Changes" }), jsx(AlertDialogDescription, { children: confirmCloseMessage })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, { onClick: () => setShowConfirmDialog(false), children: "Go Back" }), jsx(AlertDialogAction, { onClick: handleConfirmClose, children: "Exit Without Saving" })] })] }) })] }));
164
+ }
165
+
166
+ export { SelectionPanel };
@@ -5,8 +5,9 @@ declare function SheetTrigger({ ...props }: React.ComponentProps<typeof SheetPri
5
5
  declare function SheetClose({ ...props }: React.ComponentProps<typeof SheetPrimitive.Close>): import("react/jsx-runtime").JSX.Element;
6
6
  declare function SheetPortal({ ...props }: React.ComponentProps<typeof SheetPrimitive.Portal>): import("react/jsx-runtime").JSX.Element;
7
7
  declare function SheetOverlay({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Overlay>): import("react/jsx-runtime").JSX.Element;
8
- declare function SheetContent({ className, children, side, ...props }: React.ComponentProps<typeof SheetPrimitive.Content> & {
8
+ declare function SheetContent({ className, overlayClassName, children, side, ...props }: React.ComponentProps<typeof SheetPrimitive.Content> & {
9
9
  side?: "top" | "right" | "bottom" | "left";
10
+ overlayClassName?: string;
10
11
  }): import("react/jsx-runtime").JSX.Element;
11
12
  declare function SheetHeader({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
12
13
  declare function SheetFooter({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/components/sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,wBAAwB,CAAA;AAKxD,iBAAS,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,2CAE5E;AAED,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,2CAErD;AAED,iBAAS,UAAU,CAAC,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,2CAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,2CAEpD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,2CAYrD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,QAAQ,EACR,IAAc,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,GAAG;IACvD,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;CAC3C,2CA+BA;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQxE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQxE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,2CAQnD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,WAAW,CAAC,2CAQzD;AAED,OAAO,EACL,KAAK,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,CAAA"}
1
+ {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/components/sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,wBAAwB,CAAA;AAMxD,iBAAS,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,2CAE5E;AAED,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,2CAErD;AAED,iBAAS,UAAU,CAAC,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,2CAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,2CAEpD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,2CAYrD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,IAAc,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,GAAG;IACvD,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC1C,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,2CA+BA;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAQxE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAWxE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,2CAWnD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,WAAW,CAAC,2CAQzD;AAED,OAAO,EACL,KAAK,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,CAAA"}
@@ -2,6 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import * as DialogPrimitive from '@radix-ui/react-dialog';
3
3
  import { XIcon } from 'lucide-react';
4
4
  import { cn } from '../lib/utils.js';
5
+ import { PortalWrapper } from '../lib/portal-wrapper.js';
5
6
 
6
7
  function Sheet({ ...props }) {
7
8
  return jsx(DialogPrimitive.Root, { "data-slot": "sheet", ...props });
@@ -18,12 +19,12 @@ function SheetPortal({ ...props }) {
18
19
  function SheetOverlay({ className, ...props }) {
19
20
  return (jsx(DialogPrimitive.Overlay, { "data-slot": "sheet-overlay", className: cn("tw:fixed tw:inset-0 tw:z-50 tw:bg-black/50", "tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:fade-out-0 tw:data-[state=open]:fade-in-0", className), ...props }));
20
21
  }
21
- function SheetContent({ className, children, side = "right", ...props }) {
22
- return (jsxs(SheetPortal, { children: [jsx(SheetOverlay, {}), jsxs(DialogPrimitive.Content, { "data-slot": "sheet-content", className: cn("tw:fixed tw:z-50 tw:flex tw:flex-col tw:gap-4 tw:bg-background tw:shadow-lg tw:transition tw:ease-in-out", "tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:duration-300 tw:data-[state=open]:duration-500", side === "right" &&
22
+ function SheetContent({ className, overlayClassName, children, side = "right", ...props }) {
23
+ return (jsxs(SheetPortal, { children: [jsx(SheetOverlay, { className: overlayClassName }), jsx(DialogPrimitive.Content, { "data-slot": "sheet-content", className: cn("tw:fixed tw:z-50 tw:flex tw:flex-col tw:gap-4 tw:bg-background tw:shadow-lg tw:transition tw:ease-in-out", "tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:duration-300 tw:data-[state=open]:duration-500", side === "right" &&
23
24
  "tw:inset-y-0 tw:right-0 tw:h-full tw:w-3/4 tw:border-l tw:data-[state=closed]:slide-out-to-right tw:data-[state=open]:slide-in-from-right tw:sm:max-w-sm", side === "left" &&
24
25
  "tw:inset-y-0 tw:left-0 tw:h-full tw:w-3/4 tw:border-r tw:data-[state=closed]:slide-out-to-left tw:data-[state=open]:slide-in-from-left tw:sm:max-w-sm", side === "top" &&
25
26
  "tw:inset-x-0 tw:top-0 tw:h-auto tw:border-b tw:data-[state=closed]:slide-out-to-top tw:data-[state=open]:slide-in-from-top", side === "bottom" &&
26
- "tw:inset-x-0 tw:bottom-0 tw:h-auto tw:border-t tw:data-[state=closed]:slide-out-to-bottom tw:data-[state=open]:slide-in-from-bottom", className), ...props, children: [children, jsxs(DialogPrimitive.Close, { className: "tw:absolute tw:right-4 tw:top-4 tw:rounded-sm tw:opacity-70 tw:transition-opacity tw:ring-offset-background tw:hover:opacity-100 tw:focus:outline-hidden tw:focus:ring-2 tw:focus:ring-ring tw:focus:ring-offset-2 tw:data-[state=open]:bg-secondary tw:disabled:pointer-events-none", children: [jsx(XIcon, { "aria-hidden": true, className: "tw:size-4" }), jsx("span", { className: "tw:sr-only", children: "Close" })] })] })] }));
27
+ "tw:inset-x-0 tw:bottom-0 tw:h-auto tw:border-t tw:data-[state=closed]:slide-out-to-bottom tw:data-[state=open]:slide-in-from-bottom", className), ...props, children: jsxs(PortalWrapper, { children: [children, jsxs(DialogPrimitive.Close, { className: "tw:absolute tw:right-4 tw:top-4 tw:rounded-sm tw:opacity-70 tw:transition-opacity tw:ring-offset-background tw:hover:opacity-100 tw:focus:outline-hidden tw:focus:ring-2 tw:focus:ring-ring tw:focus:ring-offset-2 tw:data-[state=open]:bg-secondary tw:disabled:pointer-events-none", children: [jsx(XIcon, { "aria-hidden": true, className: "tw:size-4" }), jsx("span", { className: "tw:sr-only", children: "Close" })] })] }) })] }));
27
28
  }
28
29
  function SheetHeader({ className, ...props }) {
29
30
  return (jsx("div", { "data-slot": "sheet-header", className: cn("tw:flex tw:flex-col tw:gap-1.5 tw:p-4", className), ...props }));
@@ -32,7 +33,7 @@ function SheetFooter({ className, ...props }) {
32
33
  return (jsx("div", { "data-slot": "sheet-footer", className: cn("tw:mt-auto tw:flex tw:flex-col tw:gap-2 tw:p-4", className), ...props }));
33
34
  }
34
35
  function SheetTitle({ className, ...props }) {
35
- return (jsx(DialogPrimitive.Title, { "data-slot": "sheet-title", className: cn("tw:text-foreground tw:text-lg tw:font-semibold", className), ...props }));
36
+ return (jsx(DialogPrimitive.Title, { "data-slot": "sheet-title", className: cn("tw!:text-foreground tw!:text-lg tw!:font-semibold", className), ...props }));
36
37
  }
37
38
  function SheetDescription({ className, ...props }) {
38
39
  return (jsx(DialogPrimitive.Description, { "data-slot": "sheet-description", className: cn("tw:text-muted-foreground tw:text-sm", className), ...props }));
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ /**
3
+ * VisuallyHidden component
4
+ *
5
+ * Hides content visually while keeping it accessible to screen readers.
6
+ * This is useful for meeting accessibility requirements (like DialogTitle in Radix)
7
+ * without changing the visual design.
8
+ *
9
+ * Uses CSS positioning to move content off-screen rather than display:none,
10
+ * which would hide it from screen readers as well.
11
+ *
12
+ * @see https://www.a11yproject.com/posts/how-to-hide-content/
13
+ */
14
+ declare const VisuallyHidden: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
15
+ export { VisuallyHidden };
16
+ //# sourceMappingURL=visually-hidden.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visually-hidden.d.ts","sourceRoot":"","sources":["../../src/components/visually-hidden.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,cAAc,sKAgBlB,CAAA;AAIF,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { cn } from '../lib/utils.js';
4
+
5
+ /**
6
+ * VisuallyHidden component
7
+ *
8
+ * Hides content visually while keeping it accessible to screen readers.
9
+ * This is useful for meeting accessibility requirements (like DialogTitle in Radix)
10
+ * without changing the visual design.
11
+ *
12
+ * Uses CSS positioning to move content off-screen rather than display:none,
13
+ * which would hide it from screen readers as well.
14
+ *
15
+ * @see https://www.a11yproject.com/posts/how-to-hide-content/
16
+ */
17
+ const VisuallyHidden = React.forwardRef(({ children, className, ...props }, ref) => {
18
+ return (jsx("span", { ref: ref, className: cn("tw:absolute tw:w-px tw:h-px tw:p-0 tw:-m-px tw:overflow-hidden tw:whitespace-nowrap tw:border-0", className), ...props, children: children }));
19
+ });
20
+ VisuallyHidden.displayName = "VisuallyHidden";
21
+
22
+ export { VisuallyHidden };