@miethe/ui 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/README.md +1536 -0
- package/dist/bulk-actions/Button.d.ts +28 -0
- package/dist/bulk-actions/Button.d.ts.map +1 -0
- package/dist/bulk-actions/Button.js +45 -0
- package/dist/bulk-actions/Button.js.map +1 -0
- package/dist/bulk-actions/bulk-action-bar.d.ts +91 -0
- package/dist/bulk-actions/bulk-action-bar.d.ts.map +1 -0
- package/dist/bulk-actions/bulk-action-bar.js +94 -0
- package/dist/bulk-actions/bulk-action-bar.js.map +1 -0
- package/dist/bulk-actions/index.d.ts +5 -0
- package/dist/bulk-actions/index.d.ts.map +1 -0
- package/dist/bulk-actions/index.js +7 -0
- package/dist/bulk-actions/index.js.map +1 -0
- package/dist/bulk-actions/utils.d.ts +6 -0
- package/dist/bulk-actions/utils.d.ts.map +1 -0
- package/dist/bulk-actions/utils.js +9 -0
- package/dist/bulk-actions/utils.js.map +1 -0
- package/dist/components/ui/alert.d.ts +9 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/alert.js +23 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +34 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +7 -0
- package/dist/components/ui/collapsible.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +4 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeleton.js +7 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/content-viewer/ContentPane.d.ts +107 -0
- package/dist/content-viewer/ContentPane.d.ts.map +1 -0
- package/dist/content-viewer/ContentPane.js +247 -0
- package/dist/content-viewer/ContentPane.js.map +1 -0
- package/dist/content-viewer/ContentViewerProvider.d.ts +83 -0
- package/dist/content-viewer/ContentViewerProvider.d.ts.map +1 -0
- package/dist/content-viewer/ContentViewerProvider.js +92 -0
- package/dist/content-viewer/ContentViewerProvider.js.map +1 -0
- package/dist/content-viewer/FileTree.d.ts +71 -0
- package/dist/content-viewer/FileTree.d.ts.map +1 -0
- package/dist/content-viewer/FileTree.js +294 -0
- package/dist/content-viewer/FileTree.js.map +1 -0
- package/dist/content-viewer/adapters.d.ts +101 -0
- package/dist/content-viewer/adapters.d.ts.map +1 -0
- package/dist/content-viewer/adapters.js +32 -0
- package/dist/content-viewer/adapters.js.map +1 -0
- package/dist/content-viewer/index.d.ts +8 -0
- package/dist/content-viewer/index.d.ts.map +1 -0
- package/dist/content-viewer/index.js +5 -0
- package/dist/content-viewer/index.js.map +1 -0
- package/dist/diff/DiffViewer.d.ts +112 -0
- package/dist/diff/DiffViewer.d.ts.map +1 -0
- package/dist/diff/DiffViewer.js +414 -0
- package/dist/diff/DiffViewer.js.map +1 -0
- package/dist/diff/diff.d.ts +32 -0
- package/dist/diff/diff.d.ts.map +1 -0
- package/dist/diff/diff.js +8 -0
- package/dist/diff/diff.js.map +1 -0
- package/dist/diff/index.d.ts +4 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +3 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/display/FilePreviewPane.d.ts +31 -0
- package/dist/display/FilePreviewPane.d.ts.map +1 -0
- package/dist/display/FilePreviewPane.js +144 -0
- package/dist/display/FilePreviewPane.js.map +1 -0
- package/dist/display/FrontmatterDisplay.d.ts +33 -0
- package/dist/display/FrontmatterDisplay.d.ts.map +1 -0
- package/dist/display/FrontmatterDisplay.js +79 -0
- package/dist/display/FrontmatterDisplay.js.map +1 -0
- package/dist/display/index.d.ts +5 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +4 -0
- package/dist/display/index.js.map +1 -0
- package/dist/editor/MarkdownEditor.d.ts +28 -0
- package/dist/editor/MarkdownEditor.d.ts.map +1 -0
- package/dist/editor/MarkdownEditor.js +160 -0
- package/dist/editor/MarkdownEditor.js.map +1 -0
- package/dist/editor/SplitPreview.d.ts +28 -0
- package/dist/editor/SplitPreview.d.ts.map +1 -0
- package/dist/editor/SplitPreview.js +34 -0
- package/dist/editor/SplitPreview.js.map +1 -0
- package/dist/editor/index.d.ts +5 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +4 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/filters/filters-dropdown.d.ts +24 -0
- package/dist/filters/filters-dropdown.d.ts.map +1 -0
- package/dist/filters/filters-dropdown.js +36 -0
- package/dist/filters/filters-dropdown.js.map +1 -0
- package/dist/filters/index.d.ts +9 -0
- package/dist/filters/index.d.ts.map +1 -0
- package/dist/filters/index.js +5 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/sort-dropdown.d.ts +13 -0
- package/dist/filters/sort-dropdown.d.ts.map +1 -0
- package/dist/filters/sort-dropdown.js +20 -0
- package/dist/filters/sort-dropdown.js.map +1 -0
- package/dist/filters/tag-filter-popover.d.ts +39 -0
- package/dist/filters/tag-filter-popover.d.ts.map +1 -0
- package/dist/filters/tag-filter-popover.js +72 -0
- package/dist/filters/tag-filter-popover.js.map +1 -0
- package/dist/filters/tool-filter-popover.d.ts +42 -0
- package/dist/filters/tool-filter-popover.d.ts.map +1 -0
- package/dist/filters/tool-filter-popover.js +67 -0
- package/dist/filters/tool-filter-popover.js.map +1 -0
- package/dist/hooks/use-debounce.d.ts +9 -0
- package/dist/hooks/use-debounce.d.ts.map +1 -0
- package/dist/hooks/use-debounce.js +21 -0
- package/dist/hooks/use-debounce.js.map +1 -0
- package/dist/hooks/use-intersection-observer.d.ts +11 -0
- package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
- package/dist/hooks/use-intersection-observer.js +25 -0
- package/dist/hooks/use-intersection-observer.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/pickers/EntityPickerDialog.d.ts +233 -0
- package/dist/pickers/EntityPickerDialog.d.ts.map +1 -0
- package/dist/pickers/EntityPickerDialog.js +355 -0
- package/dist/pickers/EntityPickerDialog.js.map +1 -0
- package/dist/pickers/EntityPickerViewToggle.d.ts +8 -0
- package/dist/pickers/EntityPickerViewToggle.d.ts.map +1 -0
- package/dist/pickers/EntityPickerViewToggle.js +17 -0
- package/dist/pickers/EntityPickerViewToggle.js.map +1 -0
- package/dist/pickers/index.d.ts +5 -0
- package/dist/pickers/index.d.ts.map +1 -0
- package/dist/pickers/index.js +3 -0
- package/dist/pickers/index.js.map +1 -0
- package/dist/primitives/Badge.d.ts +16 -0
- package/dist/primitives/Badge.d.ts.map +1 -0
- package/dist/primitives/Badge.js +43 -0
- package/dist/primitives/Badge.js.map +1 -0
- package/dist/primitives/BaseArtifactModal.d.ts +114 -0
- package/dist/primitives/BaseArtifactModal.d.ts.map +1 -0
- package/dist/primitives/BaseArtifactModal.js +76 -0
- package/dist/primitives/BaseArtifactModal.js.map +1 -0
- package/dist/primitives/Dialog.d.ts +20 -0
- package/dist/primitives/Dialog.d.ts.map +1 -0
- package/dist/primitives/Dialog.js +24 -0
- package/dist/primitives/Dialog.js.map +1 -0
- package/dist/primitives/DropdownMenu.d.ts +28 -0
- package/dist/primitives/DropdownMenu.d.ts.map +1 -0
- package/dist/primitives/DropdownMenu.js +34 -0
- package/dist/primitives/DropdownMenu.js.map +1 -0
- package/dist/primitives/EnterpriseOwnerBadge.d.ts +9 -0
- package/dist/primitives/EnterpriseOwnerBadge.d.ts.map +1 -0
- package/dist/primitives/EnterpriseOwnerBadge.js +12 -0
- package/dist/primitives/EnterpriseOwnerBadge.js.map +1 -0
- package/dist/primitives/GroupedSelect.d.ts +30 -0
- package/dist/primitives/GroupedSelect.d.ts.map +1 -0
- package/dist/primitives/GroupedSelect.js +47 -0
- package/dist/primitives/GroupedSelect.js.map +1 -0
- package/dist/primitives/Input.d.ts +6 -0
- package/dist/primitives/Input.d.ts.map +1 -0
- package/dist/primitives/Input.js +9 -0
- package/dist/primitives/Input.js.map +1 -0
- package/dist/primitives/LockIcon.d.ts +11 -0
- package/dist/primitives/LockIcon.d.ts.map +1 -0
- package/dist/primitives/LockIcon.js +15 -0
- package/dist/primitives/LockIcon.js.map +1 -0
- package/dist/primitives/MaskedSecretInput.d.ts +16 -0
- package/dist/primitives/MaskedSecretInput.d.ts.map +1 -0
- package/dist/primitives/MaskedSecretInput.js +42 -0
- package/dist/primitives/MaskedSecretInput.js.map +1 -0
- package/dist/primitives/ModalHeader.d.ts +66 -0
- package/dist/primitives/ModalHeader.d.ts.map +1 -0
- package/dist/primitives/ModalHeader.js +58 -0
- package/dist/primitives/ModalHeader.js.map +1 -0
- package/dist/primitives/Popover.d.ts +9 -0
- package/dist/primitives/Popover.d.ts.map +1 -0
- package/dist/primitives/Popover.js +13 -0
- package/dist/primitives/Popover.js.map +1 -0
- package/dist/primitives/ScrollArea.d.ts +6 -0
- package/dist/primitives/ScrollArea.d.ts.map +1 -0
- package/dist/primitives/ScrollArea.js +11 -0
- package/dist/primitives/ScrollArea.js.map +1 -0
- package/dist/primitives/SearchableCombobox.d.ts +30 -0
- package/dist/primitives/SearchableCombobox.d.ts.map +1 -0
- package/dist/primitives/SearchableCombobox.js +124 -0
- package/dist/primitives/SearchableCombobox.js.map +1 -0
- package/dist/primitives/SearchablePickerDialog.d.ts +20 -0
- package/dist/primitives/SearchablePickerDialog.d.ts.map +1 -0
- package/dist/primitives/SearchablePickerDialog.js +78 -0
- package/dist/primitives/SearchablePickerDialog.js.map +1 -0
- package/dist/primitives/StatusBadge.d.ts +21 -0
- package/dist/primitives/StatusBadge.d.ts.map +1 -0
- package/dist/primitives/StatusBadge.js +25 -0
- package/dist/primitives/StatusBadge.js.map +1 -0
- package/dist/primitives/TabNavigation.d.ts +68 -0
- package/dist/primitives/TabNavigation.d.ts.map +1 -0
- package/dist/primitives/TabNavigation.js +74 -0
- package/dist/primitives/TabNavigation.js.map +1 -0
- package/dist/primitives/Tabs.d.ts +8 -0
- package/dist/primitives/Tabs.d.ts.map +1 -0
- package/dist/primitives/Tabs.js +14 -0
- package/dist/primitives/Tabs.js.map +1 -0
- package/dist/primitives/Tooltip.d.ts +8 -0
- package/dist/primitives/Tooltip.d.ts.map +1 -0
- package/dist/primitives/Tooltip.js +12 -0
- package/dist/primitives/Tooltip.js.map +1 -0
- package/dist/primitives/VerticalTabNavigation.d.ts +75 -0
- package/dist/primitives/VerticalTabNavigation.d.ts.map +1 -0
- package/dist/primitives/VerticalTabNavigation.js +166 -0
- package/dist/primitives/VerticalTabNavigation.js.map +1 -0
- package/dist/primitives/ViewModeToggle.d.ts +12 -0
- package/dist/primitives/ViewModeToggle.d.ts.map +1 -0
- package/dist/primitives/ViewModeToggle.js +56 -0
- package/dist/primitives/ViewModeToggle.js.map +1 -0
- package/dist/primitives/WizardShell.d.ts +81 -0
- package/dist/primitives/WizardShell.d.ts.map +1 -0
- package/dist/primitives/WizardShell.js +73 -0
- package/dist/primitives/WizardShell.js.map +1 -0
- package/dist/primitives/index.d.ts +38 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +24 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/primitives/utils.d.ts +6 -0
- package/dist/primitives/utils.d.ts.map +1 -0
- package/dist/primitives/utils.js +9 -0
- package/dist/primitives/utils.js.map +1 -0
- package/dist/types/index.d.ts +63 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +63 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +345 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/perf-marks.d.ts +28 -0
- package/dist/utils/perf-marks.d.ts.map +1 -0
- package/dist/utils/perf-marks.js +45 -0
- package/dist/utils/perf-marks.js.map +1 -0
- package/dist/utils/readme-utils.d.ts +67 -0
- package/dist/utils/readme-utils.d.ts.map +1 -0
- package/dist/utils/readme-utils.js +164 -0
- package/dist/utils/readme-utils.js.map +1 -0
- package/dist/utils/type-colors.d.ts +70 -0
- package/dist/utils/type-colors.d.ts.map +1 -0
- package/dist/utils/type-colors.js +118 -0
- package/dist/utils/type-colors.js.map +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Search, CheckSquare, Square } from 'lucide-react';
|
|
5
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from './Dialog';
|
|
6
|
+
import { Input } from './Input';
|
|
7
|
+
import { cn } from './utils';
|
|
8
|
+
function SearchablePickerDialogInner(props, _ref) {
|
|
9
|
+
const { open, onOpenChange, title, searchPlaceholder = 'Search…', emptyMessage = 'No items found', items, renderItem, getItemId, getItemLabel, onConfirm, onCancel, isLoading = false, } = props;
|
|
10
|
+
const [searchQuery, setSearchQuery] = React.useState('');
|
|
11
|
+
const [selectedIds, setSelectedIds] = React.useState(new Set());
|
|
12
|
+
// Reset state when dialog opens
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
if (open) {
|
|
15
|
+
setSearchQuery('');
|
|
16
|
+
setSelectedIds(new Set());
|
|
17
|
+
}
|
|
18
|
+
}, [open]);
|
|
19
|
+
const filteredItems = React.useMemo(() => {
|
|
20
|
+
if (!searchQuery.trim())
|
|
21
|
+
return items;
|
|
22
|
+
const lower = searchQuery.toLowerCase();
|
|
23
|
+
return items.filter((item) => getItemLabel(item).toLowerCase().includes(lower));
|
|
24
|
+
}, [items, searchQuery, getItemLabel]);
|
|
25
|
+
const allFilteredIds = React.useMemo(() => filteredItems.map(getItemId), [filteredItems, getItemId]);
|
|
26
|
+
const allSelected = allFilteredIds.length > 0 && allFilteredIds.every((id) => selectedIds.has(id));
|
|
27
|
+
const toggleItem = React.useCallback((id) => {
|
|
28
|
+
setSelectedIds((prev) => {
|
|
29
|
+
const next = new Set(prev);
|
|
30
|
+
if (next.has(id)) {
|
|
31
|
+
next.delete(id);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
next.add(id);
|
|
35
|
+
}
|
|
36
|
+
return next;
|
|
37
|
+
});
|
|
38
|
+
}, []);
|
|
39
|
+
const selectAll = React.useCallback(() => {
|
|
40
|
+
setSelectedIds((prev) => {
|
|
41
|
+
const next = new Set(prev);
|
|
42
|
+
allFilteredIds.forEach((id) => next.add(id));
|
|
43
|
+
return next;
|
|
44
|
+
});
|
|
45
|
+
}, [allFilteredIds]);
|
|
46
|
+
const clearAll = React.useCallback(() => {
|
|
47
|
+
setSelectedIds((prev) => {
|
|
48
|
+
const next = new Set(prev);
|
|
49
|
+
allFilteredIds.forEach((id) => next.delete(id));
|
|
50
|
+
return next;
|
|
51
|
+
});
|
|
52
|
+
}, [allFilteredIds]);
|
|
53
|
+
const handleConfirm = React.useCallback(() => {
|
|
54
|
+
onConfirm(Array.from(selectedIds));
|
|
55
|
+
}, [selectedIds, onConfirm]);
|
|
56
|
+
const handleCancel = React.useCallback(() => {
|
|
57
|
+
onCancel();
|
|
58
|
+
}, [onCancel]);
|
|
59
|
+
const handleKeyDown = React.useCallback((event) => {
|
|
60
|
+
if (event.key === 'Escape') {
|
|
61
|
+
handleCancel();
|
|
62
|
+
}
|
|
63
|
+
}, [handleCancel]);
|
|
64
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "flex max-h-[80vh] w-full max-w-md flex-col gap-0 p-0", onKeyDown: handleKeyDown, children: [_jsx(DialogHeader, { className: "border-b px-6 py-4", children: _jsx(DialogTitle, { children: title }) }), _jsx("div", { className: "border-b px-4 py-3", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { type: "text", placeholder: searchPlaceholder, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "pl-9", "aria-label": searchPlaceholder, autoFocus: true })] }) }), !isLoading && filteredItems.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 border-b px-4 py-2", children: [_jsx("button", { type: "button", onClick: allSelected ? clearAll : selectAll, className: "text-xs font-medium text-muted-foreground underline-offset-2 hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: allSelected ? 'Clear all' : 'Select all' }), selectedIds.size > 0 && (_jsxs("span", { className: "ml-auto text-xs text-muted-foreground", children: [selectedIds.size, " selected"] }))] })), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-2", role: "list", "aria-label": title, children: isLoading ? (_jsxs("div", { className: "flex items-center justify-center py-8 text-sm text-muted-foreground", children: [_jsx("span", { "aria-hidden": "true", className: "mr-2 h-4 w-4 animate-spin rounded-full border-2 border-muted-foreground/30 border-t-muted-foreground" }), "Loading\u2026"] })) : filteredItems.length === 0 ? (_jsx("p", { className: "py-8 text-center text-sm text-muted-foreground", children: emptyMessage })) : (filteredItems.map((item) => {
|
|
65
|
+
const id = getItemId(item);
|
|
66
|
+
const isSelected = selectedIds.has(id);
|
|
67
|
+
return (_jsxs("div", { role: "listitem", className: cn('flex cursor-pointer items-center gap-3 rounded-md px-2 py-2 text-sm transition-colors', 'hover:bg-accent hover:text-accent-foreground', isSelected && 'bg-accent/50'), onClick: () => toggleItem(id), onKeyDown: (e) => {
|
|
68
|
+
if (e.key === ' ' || e.key === 'Enter') {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
toggleItem(id);
|
|
71
|
+
}
|
|
72
|
+
}, tabIndex: 0, "aria-selected": isSelected, children: [isSelected ? (_jsx(CheckSquare, { className: "h-4 w-4 shrink-0 text-primary", "aria-hidden": "true" })) : (_jsx(Square, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": "true" })), _jsx("span", { className: "min-w-0 flex-1", children: renderItem(item) })] }, id));
|
|
73
|
+
})) }), _jsxs(DialogFooter, { className: "border-t px-6 py-4", children: [_jsx("button", { type: "button", onClick: handleCancel, className: cn('inline-flex h-9 items-center justify-center rounded-md border border-input px-4 text-sm font-medium', 'bg-background hover:bg-accent hover:text-accent-foreground', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', 'transition-colors'), children: "Cancel" }), _jsxs("button", { type: "button", onClick: handleConfirm, disabled: selectedIds.size === 0, className: cn('inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium', 'bg-primary text-primary-foreground hover:bg-primary/90', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', 'disabled:cursor-not-allowed disabled:opacity-50', 'transition-colors'), children: ["Confirm", selectedIds.size > 0 && (_jsxs("span", { className: "ml-1.5 tabular-nums", children: ["(", selectedIds.size, ")"] }))] })] })] }) }));
|
|
74
|
+
}
|
|
75
|
+
// Generic forwardRef workaround — same pattern as SearchableCombobox
|
|
76
|
+
const SearchablePickerDialog = React.forwardRef(SearchablePickerDialogInner);
|
|
77
|
+
export { SearchablePickerDialog };
|
|
78
|
+
//# sourceMappingURL=SearchablePickerDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchablePickerDialog.js","sourceRoot":"","sources":["../../src/primitives/SearchablePickerDialog.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BadgeProps } from './Badge';
|
|
2
|
+
export interface StatusBadgeProps extends Omit<BadgeProps, 'variant' | 'children'> {
|
|
3
|
+
/** The lifecycle status to display (e.g. "draft", "published", "deprecated"). */
|
|
4
|
+
status: string;
|
|
5
|
+
/**
|
|
6
|
+
* Optional map from status string to Badge variant.
|
|
7
|
+
* Merged on top of the default map; unknown statuses fall back to "outline".
|
|
8
|
+
*/
|
|
9
|
+
statusColorMap?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* StatusBadge — a thin wrapper around Badge that maps a lifecycle status string
|
|
13
|
+
* to a variant using a configurable color map.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <StatusBadge status="draft" />
|
|
17
|
+
* <StatusBadge status="active" statusColorMap={{ active: 'default' }} />
|
|
18
|
+
*/
|
|
19
|
+
declare function StatusBadge({ status, statusColorMap, className, ...rest }: StatusBadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export { StatusBadge };
|
|
21
|
+
//# sourceMappingURL=StatusBadge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../src/primitives/StatusBadge.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAW1C,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,UAAU,CAAC;IAChD,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,iBAAS,WAAW,CAAC,EACnB,MAAM,EACN,cAAc,EACd,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,2CAalB;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Badge } from './Badge';
|
|
3
|
+
const DEFAULT_STATUS_COLOR_MAP = {
|
|
4
|
+
draft: 'secondary',
|
|
5
|
+
published: 'default',
|
|
6
|
+
deprecated: 'destructive',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* StatusBadge — a thin wrapper around Badge that maps a lifecycle status string
|
|
10
|
+
* to a variant using a configurable color map.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <StatusBadge status="draft" />
|
|
14
|
+
* <StatusBadge status="active" statusColorMap={{ active: 'default' }} />
|
|
15
|
+
*/
|
|
16
|
+
function StatusBadge({ status, statusColorMap, className, ...rest }) {
|
|
17
|
+
const map = statusColorMap
|
|
18
|
+
? { ...DEFAULT_STATUS_COLOR_MAP, ...statusColorMap }
|
|
19
|
+
: DEFAULT_STATUS_COLOR_MAP;
|
|
20
|
+
const variant = map[status] ?? 'outline';
|
|
21
|
+
const displayText = status.charAt(0).toUpperCase() + status.slice(1);
|
|
22
|
+
return (_jsx(Badge, { variant: variant, className: className, ...rest, children: displayText }));
|
|
23
|
+
}
|
|
24
|
+
export { StatusBadge };
|
|
25
|
+
//# sourceMappingURL=StatusBadge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBadge.js","sourceRoot":"","sources":["../../src/primitives/StatusBadge.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAMhC,MAAM,wBAAwB,GAAiC;IAC7D,KAAK,EAAE,WAAW;IAClB,SAAS,EAAE,SAAS;IACpB,UAAU,EAAE,aAAa;CAC1B,CAAC;AAaF;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,EACnB,MAAM,EACN,cAAc,EACd,SAAS,EACT,GAAG,IAAI,EACU;IACjB,MAAM,GAAG,GAAG,cAAc;QACxB,CAAC,CAAC,EAAE,GAAG,wBAAwB,EAAE,GAAG,cAAc,EAAE;QACpD,CAAC,CAAC,wBAAwB,CAAC;IAE7B,MAAM,OAAO,GAAI,GAAG,CAAC,MAAM,CAA8B,IAAI,SAAS,CAAC;IACvE,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAErE,OAAO,CACL,KAAC,KAAK,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,KAAM,IAAI,YACpD,WAAW,GACN,CACT,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tab Navigation Component
|
|
3
|
+
*
|
|
4
|
+
* A styled tab list for modal tabs with underline style (not rounded).
|
|
5
|
+
* Uses Radix UI Tabs primitives with custom styling for consistent modal navigation.
|
|
6
|
+
*
|
|
7
|
+
* @example Basic usage
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <Tabs value={activeTab} onValueChange={setActiveTab}>
|
|
10
|
+
* <TabNavigation
|
|
11
|
+
* tabs={[
|
|
12
|
+
* { value: 'overview', label: 'Overview' },
|
|
13
|
+
* { value: 'settings', label: 'Settings' },
|
|
14
|
+
* ]}
|
|
15
|
+
* />
|
|
16
|
+
* <TabsContent value="overview">...</TabsContent>
|
|
17
|
+
* <TabsContent value="settings">...</TabsContent>
|
|
18
|
+
* </Tabs>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example With icons and badges
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <TabNavigation
|
|
24
|
+
* tabs={[
|
|
25
|
+
* { value: 'overview', label: 'Overview', icon: Info },
|
|
26
|
+
* { value: 'files', label: 'Files', icon: FileText, badge: 12 },
|
|
27
|
+
* { value: 'disabled', label: 'Coming Soon', disabled: true },
|
|
28
|
+
* ]}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import * as React from 'react';
|
|
33
|
+
export interface Tab {
|
|
34
|
+
/** Unique identifier for the tab */
|
|
35
|
+
value: string;
|
|
36
|
+
/** Display label for the tab */
|
|
37
|
+
label: string;
|
|
38
|
+
/** Optional icon component */
|
|
39
|
+
icon?: React.ComponentType<{
|
|
40
|
+
className?: string;
|
|
41
|
+
}>;
|
|
42
|
+
/** Optional badge count to display */
|
|
43
|
+
badge?: number;
|
|
44
|
+
/** Whether the tab is disabled */
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface TabNavigationProps {
|
|
48
|
+
/** Array of tab configurations */
|
|
49
|
+
tabs: Tab[];
|
|
50
|
+
/** Additional CSS classes for the TabsList container */
|
|
51
|
+
className?: string;
|
|
52
|
+
/** Accessible label for the tab list */
|
|
53
|
+
ariaLabel?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* TabNavigation - Underline-styled tab list for modals
|
|
57
|
+
*
|
|
58
|
+
* Renders a horizontal tab list with underline styling instead of
|
|
59
|
+
* the default rounded pill style. Supports icons, badges, and disabled states.
|
|
60
|
+
*
|
|
61
|
+
* Must be used within a Tabs component from @radix-ui/react-tabs.
|
|
62
|
+
*
|
|
63
|
+
* @param tabs - Array of tab configurations
|
|
64
|
+
* @param className - Additional CSS classes for the container
|
|
65
|
+
* @param ariaLabel - Accessible label for the tab list
|
|
66
|
+
*/
|
|
67
|
+
export declare function TabNavigation({ tabs, className, ariaLabel, }: TabNavigationProps): import("react/jsx-runtime").JSX.Element;
|
|
68
|
+
//# sourceMappingURL=TabNavigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabNavigation.d.ts","sourceRoot":"","sources":["../../src/primitives/TabNavigation.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,MAAM,WAAW,GAAG;IAClB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,SAAS,EACT,SAA6B,GAC9B,EAAE,kBAAkB,2CAsDpB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tab Navigation Component
|
|
3
|
+
*
|
|
4
|
+
* A styled tab list for modal tabs with underline style (not rounded).
|
|
5
|
+
* Uses Radix UI Tabs primitives with custom styling for consistent modal navigation.
|
|
6
|
+
*
|
|
7
|
+
* @example Basic usage
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <Tabs value={activeTab} onValueChange={setActiveTab}>
|
|
10
|
+
* <TabNavigation
|
|
11
|
+
* tabs={[
|
|
12
|
+
* { value: 'overview', label: 'Overview' },
|
|
13
|
+
* { value: 'settings', label: 'Settings' },
|
|
14
|
+
* ]}
|
|
15
|
+
* />
|
|
16
|
+
* <TabsContent value="overview">...</TabsContent>
|
|
17
|
+
* <TabsContent value="settings">...</TabsContent>
|
|
18
|
+
* </Tabs>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example With icons and badges
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <TabNavigation
|
|
24
|
+
* tabs={[
|
|
25
|
+
* { value: 'overview', label: 'Overview', icon: Info },
|
|
26
|
+
* { value: 'files', label: 'Files', icon: FileText, badge: 12 },
|
|
27
|
+
* { value: 'disabled', label: 'Coming Soon', disabled: true },
|
|
28
|
+
* ]}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
'use client';
|
|
33
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
34
|
+
import { cn } from './utils';
|
|
35
|
+
import { TabsList, TabsTrigger } from './Tabs';
|
|
36
|
+
import { Badge } from './Badge';
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Component
|
|
39
|
+
// ============================================================================
|
|
40
|
+
/**
|
|
41
|
+
* TabNavigation - Underline-styled tab list for modals
|
|
42
|
+
*
|
|
43
|
+
* Renders a horizontal tab list with underline styling instead of
|
|
44
|
+
* the default rounded pill style. Supports icons, badges, and disabled states.
|
|
45
|
+
*
|
|
46
|
+
* Must be used within a Tabs component from @radix-ui/react-tabs.
|
|
47
|
+
*
|
|
48
|
+
* @param tabs - Array of tab configurations
|
|
49
|
+
* @param className - Additional CSS classes for the container
|
|
50
|
+
* @param ariaLabel - Accessible label for the tab list
|
|
51
|
+
*/
|
|
52
|
+
export function TabNavigation({ tabs, className, ariaLabel = 'Navigation tabs', }) {
|
|
53
|
+
return (_jsx(TabsList, { className: cn(
|
|
54
|
+
// Override default rounded/background styling for underline style
|
|
55
|
+
'h-auto w-full justify-start gap-0 rounded-none border-b bg-transparent p-0', className), "aria-label": ariaLabel, children: tabs.map((tab) => {
|
|
56
|
+
const Icon = tab.icon;
|
|
57
|
+
return (_jsxs(TabsTrigger, { value: tab.value, disabled: tab.disabled, className: cn(
|
|
58
|
+
// Base styles
|
|
59
|
+
'relative inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium',
|
|
60
|
+
// Remove default rounded styling
|
|
61
|
+
'rounded-none border-b-2 border-transparent bg-transparent shadow-none',
|
|
62
|
+
// Active state - underline instead of background
|
|
63
|
+
'data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none',
|
|
64
|
+
// Inactive/hover states
|
|
65
|
+
'text-muted-foreground hover:text-foreground',
|
|
66
|
+
// Disabled state
|
|
67
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
68
|
+
// Focus ring
|
|
69
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2'), "aria-label": tab.badge !== undefined && tab.badge > 0
|
|
70
|
+
? `${tab.label}, ${tab.badge} items`
|
|
71
|
+
: undefined, children: [Icon && _jsx(Icon, { className: "h-4 w-4 flex-shrink-0", "aria-hidden": "true" }), _jsx("span", { children: tab.label }), typeof tab.badge === 'number' && tab.badge > 0 && (_jsx(Badge, { variant: "secondary", className: "ml-1 h-5 min-w-[1.25rem] px-1.5 text-xs", "aria-hidden": "true", children: tab.badge > 99 ? '99+' : tab.badge }))] }, tab.value));
|
|
72
|
+
}) }));
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=TabNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabNavigation.js","sourceRoot":"","sources":["../../src/primitives/TabNavigation.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,YAAY,CAAC;;AAGb,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AA4BhC,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,IAAI,EACJ,SAAS,EACT,SAAS,GAAG,iBAAiB,GACV;IACnB,OAAO,CACL,KAAC,QAAQ,IACP,SAAS,EAAE,EAAE;QACX,kEAAkE;QAClE,4EAA4E,EAC5E,SAAS,CACV,gBACW,SAAS,YAEpB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAChB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;YAEtB,OAAO,CACL,MAAC,WAAW,IAEV,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,EACtB,SAAS,EAAE,EAAE;gBACX,cAAc;gBACd,yEAAyE;gBACzE,iCAAiC;gBACjC,uEAAuE;gBACvE,iDAAiD;gBACjD,2IAA2I;gBAC3I,wBAAwB;gBACxB,6CAA6C;gBAC7C,iBAAiB;gBACjB,iDAAiD;gBACjD,aAAa;gBACb,qGAAqG,CACtG,gBAEC,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC;oBACtC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,QAAQ;oBACpC,CAAC,CAAC,SAAS,aAGd,IAAI,IAAI,KAAC,IAAI,IAAC,SAAS,EAAC,uBAAuB,iBAAa,MAAM,GAAG,EACtE,yBAAO,GAAG,CAAC,KAAK,GAAQ,EACvB,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,CACjD,KAAC,KAAK,IACJ,OAAO,EAAC,WAAW,EACnB,SAAS,EAAC,yCAAyC,iBACvC,MAAM,YAEjB,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAC7B,CACT,KAjCI,GAAG,CAAC,KAAK,CAkCF,CACf,CAAC;QACJ,CAAC,CAAC,GACO,CACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
3
|
+
declare const Tabs: React.ForwardRefExoticComponent<TabsPrimitive.TabsProps & React.RefAttributes<HTMLDivElement>>;
|
|
4
|
+
declare const TabsList: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
5
|
+
declare const TabsTrigger: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
6
|
+
declare const TabsContent: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
8
|
+
//# sourceMappingURL=Tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../src/primitives/Tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AAItD,QAAA,MAAM,IAAI,gGAAqB,CAAC;AAEhC,QAAA,MAAM,QAAQ,uJAYZ,CAAC;AAGH,QAAA,MAAM,WAAW,gKAYf,CAAC;AAGH,QAAA,MAAM,WAAW,0JAYf,CAAC;AAGH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
5
|
+
import { cn } from './utils';
|
|
6
|
+
const Tabs = TabsPrimitive.Root;
|
|
7
|
+
const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn('inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground', className), ...props })));
|
|
8
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
9
|
+
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn('inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow', className), ...props })));
|
|
10
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
11
|
+
const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn('mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', className), ...props })));
|
|
12
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
13
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
14
|
+
//# sourceMappingURL=Tabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../src/primitives/Tabs.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC;AAEhC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAG/B,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClC,KAAC,aAAa,CAAC,IAAI,IACjB,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CACX,2FAA2F,EAC3F,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAC;AACH,QAAQ,CAAC,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;AAEtD,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAGlC,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClC,KAAC,aAAa,CAAC,OAAO,IACpB,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CACX,gYAAgY,EAChY,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAC;AACH,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC;AAE5D,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAGlC,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClC,KAAC,aAAa,CAAC,OAAO,IACpB,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CACX,iIAAiI,EACjI,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAC;AACH,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC;AAE5D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
3
|
+
declare const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps>;
|
|
4
|
+
declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
|
|
5
|
+
declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
6
|
+
declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
8
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../src/primitives/Tooltip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAI5D,QAAA,MAAM,eAAe,iDAA4B,CAAC;AAElD,QAAA,MAAM,OAAO,yCAAwB,CAAC;AAEtC,QAAA,MAAM,cAAc,gHAA2B,CAAC;AAEhD,QAAA,MAAM,cAAc,gKAalB,CAAC;AAGH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
5
|
+
import { cn } from './utils';
|
|
6
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
7
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
8
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
9
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn('z-50 origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', className), ...props })));
|
|
10
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
11
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
12
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../src/primitives/Tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,eAAe,GAAG,gBAAgB,CAAC,QAAQ,CAAC;AAElD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAEtC,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,CAAC;AAEhD,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAGrC,CAAC,EAAE,SAAS,EAAE,UAAU,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAClD,KAAC,gBAAgB,CAAC,OAAO,IACvB,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,EAAE,CACX,sbAAsb,EACtb,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAC,CAAC;AACH,cAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC;AAElE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical Tab Navigation Component
|
|
3
|
+
*
|
|
4
|
+
* A standalone vertical tab list with keyboard navigation and ARIA attributes.
|
|
5
|
+
* Unlike TabNavigation (which wraps Radix TabsList), this component manages its
|
|
6
|
+
* own focus and activation logic so it can be used outside a Radix Tabs context —
|
|
7
|
+
* useful for sidebar navigation panels where the tab panel is rendered elsewhere.
|
|
8
|
+
*
|
|
9
|
+
* @example Basic usage
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const [activeTab, setActiveTab] = React.useState('overview');
|
|
12
|
+
*
|
|
13
|
+
* <VerticalTabNavigation
|
|
14
|
+
* tabs={[
|
|
15
|
+
* { value: 'overview', label: 'Overview', icon: Info },
|
|
16
|
+
* { value: 'settings', label: 'Settings', icon: Settings },
|
|
17
|
+
* ]}
|
|
18
|
+
* activeTab={activeTab}
|
|
19
|
+
* onTabChange={setActiveTab}
|
|
20
|
+
* ariaLabel="Artifact detail navigation"
|
|
21
|
+
* />
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example With badges and disabled tabs
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <VerticalTabNavigation
|
|
27
|
+
* tabs={[
|
|
28
|
+
* { value: 'files', label: 'Files', icon: FileText, badge: 12 },
|
|
29
|
+
* { value: 'preview', label: 'Coming Soon', disabled: true },
|
|
30
|
+
* ]}
|
|
31
|
+
* activeTab={activeTab}
|
|
32
|
+
* onTabChange={setActiveTab}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import * as React from 'react';
|
|
37
|
+
export type { Tab } from './TabNavigation';
|
|
38
|
+
import type { Tab } from './TabNavigation';
|
|
39
|
+
export interface VerticalTabNavigationProps {
|
|
40
|
+
/** Array of tab configurations */
|
|
41
|
+
tabs: Tab[];
|
|
42
|
+
/** Currently active tab value */
|
|
43
|
+
activeTab: string;
|
|
44
|
+
/** Callback invoked when the user selects a tab */
|
|
45
|
+
onTabChange: (tabId: string) => void;
|
|
46
|
+
/** Additional CSS classes for the container */
|
|
47
|
+
className?: string;
|
|
48
|
+
/** Accessible label for the tab list */
|
|
49
|
+
ariaLabel?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Imperative handle exposed via forwardRef for programmatic focus control. */
|
|
52
|
+
export interface VerticalTabNavigationHandle {
|
|
53
|
+
/** Focus the first enabled tab button without changing the active tab. */
|
|
54
|
+
focusFirstTab: () => void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* VerticalTabNavigation — forward-ref enabled version of the component.
|
|
58
|
+
*
|
|
59
|
+
* Allows consumers to access the imperative handle for programmatic focus control
|
|
60
|
+
* via the `ref` prop.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const navRef = React.useRef<VerticalTabNavigationHandle>(null);
|
|
65
|
+
*
|
|
66
|
+
* // Focus the first tab when lens changes, without changing activeTab
|
|
67
|
+
* React.useEffect(() => {
|
|
68
|
+
* navRef.current?.focusFirstTab();
|
|
69
|
+
* }, [activeLens]);
|
|
70
|
+
*
|
|
71
|
+
* return <VerticalTabNavigation ref={navRef} tabs={tabs} activeTab={activeTab} ... />
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare const VerticalTabNavigation: React.ForwardRefExoticComponent<VerticalTabNavigationProps & React.RefAttributes<VerticalTabNavigationHandle>>;
|
|
75
|
+
//# sourceMappingURL=VerticalTabNavigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VerticalTabNavigation.d.ts","sourceRoot":"","sources":["../../src/primitives/VerticalTabNavigation.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,YAAY,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,0BAA0B;IACzC,kCAAkC;IAClC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AA8KD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,gHAA6B,CAAC"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical Tab Navigation Component
|
|
3
|
+
*
|
|
4
|
+
* A standalone vertical tab list with keyboard navigation and ARIA attributes.
|
|
5
|
+
* Unlike TabNavigation (which wraps Radix TabsList), this component manages its
|
|
6
|
+
* own focus and activation logic so it can be used outside a Radix Tabs context —
|
|
7
|
+
* useful for sidebar navigation panels where the tab panel is rendered elsewhere.
|
|
8
|
+
*
|
|
9
|
+
* @example Basic usage
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const [activeTab, setActiveTab] = React.useState('overview');
|
|
12
|
+
*
|
|
13
|
+
* <VerticalTabNavigation
|
|
14
|
+
* tabs={[
|
|
15
|
+
* { value: 'overview', label: 'Overview', icon: Info },
|
|
16
|
+
* { value: 'settings', label: 'Settings', icon: Settings },
|
|
17
|
+
* ]}
|
|
18
|
+
* activeTab={activeTab}
|
|
19
|
+
* onTabChange={setActiveTab}
|
|
20
|
+
* ariaLabel="Artifact detail navigation"
|
|
21
|
+
* />
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example With badges and disabled tabs
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <VerticalTabNavigation
|
|
27
|
+
* tabs={[
|
|
28
|
+
* { value: 'files', label: 'Files', icon: FileText, badge: 12 },
|
|
29
|
+
* { value: 'preview', label: 'Coming Soon', disabled: true },
|
|
30
|
+
* ]}
|
|
31
|
+
* activeTab={activeTab}
|
|
32
|
+
* onTabChange={setActiveTab}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
'use client';
|
|
37
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
38
|
+
import * as React from 'react';
|
|
39
|
+
import { cn } from './utils';
|
|
40
|
+
import { Badge } from './Badge';
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Component
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* VerticalTabNavigation — standalone vertical tab list with full keyboard support.
|
|
46
|
+
*
|
|
47
|
+
* Implements the WAI-ARIA Tabs pattern with vertical orientation:
|
|
48
|
+
* - ArrowDown / ArrowUp navigate between enabled tabs (wraps around).
|
|
49
|
+
* - Home / End jump to first / last enabled tab.
|
|
50
|
+
* - Focus automatically activates the tab (roving tabindex pattern).
|
|
51
|
+
* - Tab key exits the tab list entirely (standard browser behavior).
|
|
52
|
+
*
|
|
53
|
+
* @param tabs - Array of tab configurations (value, label, icon, badge, disabled)
|
|
54
|
+
* @param activeTab - Controlled active tab value
|
|
55
|
+
* @param onTabChange - Callback fired when a tab becomes active
|
|
56
|
+
* @param className - Additional CSS classes for the container div
|
|
57
|
+
* @param ariaLabel - Accessible label for the tab list element
|
|
58
|
+
*
|
|
59
|
+
* Exposes a `VerticalTabNavigationHandle` via `forwardRef` with:
|
|
60
|
+
* - `focusFirstTab()` — moves focus to the first enabled tab without changing
|
|
61
|
+
* the active tab value. Useful when the tab list is swapped (e.g. lens change)
|
|
62
|
+
* and focus needs to follow the new content.
|
|
63
|
+
*/
|
|
64
|
+
const VerticalTabNavigationInner = React.forwardRef(function VerticalTabNavigation({ tabs, activeTab, onTabChange, className, ariaLabel = 'Navigation tabs', }, ref) {
|
|
65
|
+
// Refs for each button so we can programmatically move focus.
|
|
66
|
+
const buttonRefs = React.useRef(new Map());
|
|
67
|
+
const enabledTabs = React.useMemo(() => tabs.filter((t) => !t.disabled), [tabs]);
|
|
68
|
+
// Expose imperative handle so parents can focus the first tab on demand
|
|
69
|
+
// (e.g. when a lens change swaps the visible tab list).
|
|
70
|
+
React.useImperativeHandle(ref, () => ({
|
|
71
|
+
focusFirstTab: () => {
|
|
72
|
+
const first = enabledTabs[0];
|
|
73
|
+
if (first) {
|
|
74
|
+
buttonRefs.current.get(first.value)?.focus();
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
}), [enabledTabs]);
|
|
78
|
+
const focusAndActivate = React.useCallback((tabValue) => {
|
|
79
|
+
onTabChange(tabValue);
|
|
80
|
+
buttonRefs.current.get(tabValue)?.focus();
|
|
81
|
+
}, [onTabChange]);
|
|
82
|
+
// WAI-ARIA Tabs pattern keyboard handler.
|
|
83
|
+
// Implements arrow key navigation (wraps around), Home/End jumping, and focus-activates
|
|
84
|
+
// the roving tabindex pattern (only one tab is ever in the tab order at a time).
|
|
85
|
+
const handleKeyDown = React.useCallback((event, currentValue) => {
|
|
86
|
+
const currentIndex = enabledTabs.findIndex((t) => t.value === currentValue);
|
|
87
|
+
switch (event.key) {
|
|
88
|
+
case 'ArrowDown': {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
const next = enabledTabs[(currentIndex + 1) % enabledTabs.length];
|
|
91
|
+
if (next)
|
|
92
|
+
focusAndActivate(next.value);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case 'ArrowUp': {
|
|
96
|
+
event.preventDefault();
|
|
97
|
+
const prev = enabledTabs[(currentIndex - 1 + enabledTabs.length) % enabledTabs.length];
|
|
98
|
+
if (prev)
|
|
99
|
+
focusAndActivate(prev.value);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'Home': {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
const first = enabledTabs[0];
|
|
105
|
+
if (first)
|
|
106
|
+
focusAndActivate(first.value);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'End': {
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
const last = enabledTabs[enabledTabs.length - 1];
|
|
112
|
+
if (last)
|
|
113
|
+
focusAndActivate(last.value);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
default:
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}, [enabledTabs, focusAndActivate]);
|
|
120
|
+
return (_jsx("div", { role: "tablist", "aria-orientation": "vertical", "aria-label": ariaLabel, className: cn('flex flex-col', className), children: tabs.map((tab) => {
|
|
121
|
+
const Icon = tab.icon;
|
|
122
|
+
const isActive = tab.value === activeTab;
|
|
123
|
+
return (_jsxs("button", { ref: (el) => {
|
|
124
|
+
if (el) {
|
|
125
|
+
buttonRefs.current.set(tab.value, el);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
buttonRefs.current.delete(tab.value);
|
|
129
|
+
}
|
|
130
|
+
}, role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.value}`, "aria-disabled": tab.disabled, tabIndex: isActive ? 0 : -1, disabled: tab.disabled, onClick: () => !tab.disabled && onTabChange(tab.value), onKeyDown: (e) => !tab.disabled && handleKeyDown(e, tab.value), "aria-label": tab.badge !== undefined && tab.badge > 0
|
|
131
|
+
? `${tab.label}, ${tab.badge} items`
|
|
132
|
+
: undefined, className: cn(
|
|
133
|
+
// Base
|
|
134
|
+
'flex items-center gap-2 px-3 py-2 text-sm rounded-r-md w-full text-left',
|
|
135
|
+
// Transition
|
|
136
|
+
'transition-colors',
|
|
137
|
+
// Active state
|
|
138
|
+
isActive
|
|
139
|
+
? 'border-l-2 border-primary bg-accent text-foreground font-medium'
|
|
140
|
+
: 'border-l-2 border-transparent text-muted-foreground hover:bg-accent/50',
|
|
141
|
+
// Disabled state
|
|
142
|
+
tab.disabled && 'cursor-not-allowed opacity-50',
|
|
143
|
+
// Focus ring
|
|
144
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2'), children: [Icon && _jsx(Icon, { className: "h-4 w-4 flex-shrink-0", "aria-hidden": "true" }), _jsx("span", { className: "flex-1 text-sm", children: tab.label }), typeof tab.badge === 'number' && tab.badge > 0 && (_jsx(Badge, { variant: "secondary", className: "ml-1 h-5 min-w-[1.25rem] px-1.5 text-xs", "aria-hidden": "true", children: tab.badge > 99 ? '99+' : tab.badge }))] }, tab.value));
|
|
145
|
+
}) }));
|
|
146
|
+
});
|
|
147
|
+
/**
|
|
148
|
+
* VerticalTabNavigation — forward-ref enabled version of the component.
|
|
149
|
+
*
|
|
150
|
+
* Allows consumers to access the imperative handle for programmatic focus control
|
|
151
|
+
* via the `ref` prop.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```tsx
|
|
155
|
+
* const navRef = React.useRef<VerticalTabNavigationHandle>(null);
|
|
156
|
+
*
|
|
157
|
+
* // Focus the first tab when lens changes, without changing activeTab
|
|
158
|
+
* React.useEffect(() => {
|
|
159
|
+
* navRef.current?.focusFirstTab();
|
|
160
|
+
* }, [activeLens]);
|
|
161
|
+
*
|
|
162
|
+
* return <VerticalTabNavigation ref={navRef} tabs={tabs} activeTab={activeTab} ... />
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export const VerticalTabNavigation = VerticalTabNavigationInner;
|
|
166
|
+
//# sourceMappingURL=VerticalTabNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VerticalTabNavigation.js","sourceRoot":"","sources":["../../src/primitives/VerticalTabNavigation.tsx"],"names":[],"mappings":"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"}
|