@dreamtree-org/twreact-ui 1.2.1 → 1.3.1
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/DESIGN.md +118 -0
- package/README.md +231 -44
- package/ai-skills/dreamtree-ui.md +98 -12
- package/dist/ai-schema.json +452 -17
- package/dist/components/blocks/AppShell.d.ts +4 -0
- package/dist/components/blocks/AppShell.d.ts.map +1 -0
- package/dist/components/blocks/ConfirmDialog.d.ts +4 -0
- package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/blocks/EmptyState.d.ts +4 -0
- package/dist/components/blocks/EmptyState.d.ts.map +1 -0
- package/dist/components/blocks/ErrorState.d.ts +4 -0
- package/dist/components/blocks/ErrorState.d.ts.map +1 -0
- package/dist/components/blocks/LoadingState.d.ts +9 -0
- package/dist/components/blocks/LoadingState.d.ts.map +1 -0
- package/dist/components/blocks/PageHeader.d.ts +4 -0
- package/dist/components/blocks/PageHeader.d.ts.map +1 -0
- package/dist/components/blocks/StatCard.d.ts +4 -0
- package/dist/components/blocks/StatCard.d.ts.map +1 -0
- package/dist/components/blocks/StatusPill.d.ts +5 -0
- package/dist/components/blocks/StatusPill.d.ts.map +1 -0
- package/dist/components/core/Accordion.d.ts.map +1 -1
- package/dist/components/core/Button.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/ColorPicker.d.ts.map +1 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.d.ts.map +1 -1
- package/dist/components/core/Form.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/Popover.d.ts +4 -0
- package/dist/components/core/Popover.d.ts.map +1 -0
- package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Radio.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts +4 -0
- package/dist/components/core/Slider.d.ts.map +1 -0
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
- package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +2 -2
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +4 -2
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts +4 -0
- package/dist/components/core/Textarea.d.ts.map +1 -0
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts +4 -0
- package/dist/components/feedback/Drawer.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +14 -5
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/Tour.d.ts +4 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -0
- package/dist/components/feedback/TourSpotlight.d.ts +9 -0
- package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +8 -2
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts +4 -0
- package/dist/components/utility/Sortable.d.ts.map +1 -0
- package/dist/esm/_vendor/object-assign/index.js +99 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
- package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
- package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
- package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
- package/dist/esm/_vendor/prop-types/index.js +30 -0
- package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
- package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
- package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/index.js +3 -0
- package/dist/esm/_virtual/index2.js +3 -0
- package/dist/esm/_virtual/react-is.development.js +3 -0
- package/dist/esm/_virtual/react-is.production.min.js +3 -0
- package/dist/esm/components/blocks/AppShell.js +205 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
- package/dist/esm/components/blocks/EmptyState.js +44 -0
- package/dist/esm/components/blocks/ErrorState.js +53 -0
- package/dist/esm/components/blocks/LoadingState.js +134 -0
- package/dist/esm/components/blocks/PageHeader.js +51 -0
- package/dist/esm/components/blocks/StatCard.js +79 -0
- package/dist/esm/components/blocks/StatusPill.js +55 -0
- package/dist/esm/components/core/Accordion.js +260 -0
- package/dist/esm/components/core/Button.js +59 -0
- package/dist/esm/components/core/Checkbox.js +188 -0
- package/dist/esm/components/core/ColorPicker.js +348 -0
- package/dist/esm/components/core/DatePicker.js +436 -0
- package/dist/esm/components/core/DateRangePicker.js +494 -0
- package/dist/esm/components/core/Form.js +522 -0
- package/dist/esm/components/core/Input.js +179 -0
- package/dist/esm/components/core/Loader.js +141 -0
- package/dist/esm/components/core/LocationPicker.js +161 -0
- package/dist/esm/components/core/Popover.js +171 -0
- package/dist/esm/components/core/PriceRangePicker.js +376 -0
- package/dist/esm/components/core/ProgressBar.js +152 -0
- package/dist/esm/components/core/Radio.js +156 -0
- package/dist/esm/components/core/Rate.js +197 -0
- package/dist/esm/components/core/RoundedTag.js +118 -0
- package/dist/esm/components/core/Select.js +857 -0
- package/dist/esm/components/core/Skeleton.js +100 -0
- package/dist/esm/components/core/Slider.js +134 -0
- package/dist/esm/components/core/SpeechToText.js +226 -0
- package/dist/esm/components/core/Switch.js +207 -0
- package/dist/esm/components/core/Table/ActionMenu.js +251 -0
- package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
- package/dist/esm/components/core/Table/FieldInput.js +157 -0
- package/dist/esm/components/core/Table/MobileCard.js +187 -0
- package/dist/esm/components/core/Table/MobileFilters.js +72 -0
- package/dist/esm/components/core/Table/Pagination.js +157 -0
- package/dist/esm/components/core/Table/Table.js +1533 -0
- package/dist/esm/components/core/Table/TableRow.js +254 -0
- package/dist/esm/components/core/Table/constants.js +35 -0
- package/dist/esm/components/core/Table/helpers.js +124 -0
- package/dist/esm/components/core/Table/useClickOutside.js +26 -0
- package/dist/esm/components/core/Tabs.js +289 -0
- package/dist/esm/components/core/TextToSpeech.js +52 -0
- package/dist/esm/components/core/Textarea.js +125 -0
- package/dist/esm/components/core/ThreeDotPopover.js +160 -0
- package/dist/esm/components/core/Tooltip.js +372 -0
- package/dist/esm/components/feedback/Alert.js +96 -0
- package/dist/esm/components/feedback/Dialog.js +200 -0
- package/dist/esm/components/feedback/Drawer.js +171 -0
- package/dist/esm/components/feedback/Toast.js +362 -0
- package/dist/esm/components/feedback/Tour.js +214 -0
- package/dist/esm/components/feedback/TourSpotlight.js +71 -0
- package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
- package/dist/esm/components/navigation/Dropdown.js +53 -0
- package/dist/esm/components/navigation/FootNav.js +51 -0
- package/dist/esm/components/navigation/Navbar.js +437 -0
- package/dist/esm/components/navigation/Sidebar.js +567 -0
- package/dist/esm/components/utility/Avatar.js +89 -0
- package/dist/esm/components/utility/Badge.js +47 -0
- package/dist/esm/components/utility/Card.js +85 -0
- package/dist/esm/components/utility/Carousel.js +97 -0
- package/dist/esm/components/utility/Condition.js +9 -0
- package/dist/esm/components/utility/FileUpload.js +177 -0
- package/dist/esm/components/utility/Pagination.js +111 -0
- package/dist/esm/components/utility/Sortable.js +190 -0
- package/dist/esm/components/utility/Stepper.js +101 -0
- package/dist/esm/hooks/useApi.js +169 -0
- package/dist/esm/hooks/useControllableState.js +32 -0
- package/dist/esm/hooks/useFocusTrap.js +85 -0
- package/dist/esm/hooks/useLatestRef.js +20 -0
- package/dist/esm/hooks/useMixins.js +100 -0
- package/dist/esm/hooks/useScrollLock.js +26 -0
- package/dist/esm/hooks/useSliderValues.js +135 -0
- package/dist/esm/hooks/useSortable.js +188 -0
- package/dist/esm/hooks/useTheme.js +53 -0
- package/dist/esm/hooks/useTourTarget.js +92 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/store/index.js +26 -0
- package/dist/esm/store/store.js +107 -0
- package/dist/esm/store/storeSlice.js +45 -0
- package/dist/esm/utils/cn.js +11 -0
- package/dist/esm/utils/emitter.js +169 -0
- package/dist/esm/utils/helpers.js +161 -0
- package/dist/esm/utils/position.js +134 -0
- package/dist/hooks/useApi.d.ts +2 -1
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useControllableState.d.ts +11 -0
- package/dist/hooks/useControllableState.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +15 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/hooks/useLatestRef.d.ts +8 -0
- package/dist/hooks/useLatestRef.d.ts.map +1 -0
- package/dist/hooks/useMixins.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.d.ts +2 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -0
- package/dist/hooks/useSliderValues.d.ts +43 -0
- package/dist/hooks/useSliderValues.d.ts.map +1 -0
- package/dist/hooks/useSortable.d.ts +32 -0
- package/dist/hooks/useSortable.d.ts.map +1 -0
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTourTarget.d.ts +15 -0
- package/dist/hooks/useTourTarget.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +55 -39
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +7937 -4659
- package/dist/index.js +7950 -4657
- package/dist/tokens/brands/default.css +1 -0
- package/dist/tokens/brands/default.json +5 -0
- package/dist/tokens/brands/practicepro.css +17 -0
- package/dist/tokens/brands/practicepro.json +27 -0
- package/dist/tokens/tailwind3-preset.cjs +214 -0
- package/dist/tokens/theme.css +193 -0
- package/dist/tokens/tokens.json +373 -0
- package/dist/tokens/vars.css +98 -0
- package/dist/types/blocks.d.ts +109 -0
- package/dist/types/blocks.d.ts.map +1 -0
- package/dist/types/index.d.ts +194 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/position.d.ts +30 -0
- package/dist/utils/position.d.ts.map +1 -0
- package/doc/README.md +26 -1
- package/mcp/catalog.snapshot.json +1643 -549
- package/package.json +24 -6
- package/tokens/brands/default.json +5 -0
- package/tokens/brands/practicepro.json +27 -0
- package/tokens/lib.cjs +128 -0
- package/tokens/tokens.json +133 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useMemo, useState, useEffect, useId, useRef, useLayoutEffect } from 'react';
|
|
5
|
+
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { ChevronRight, ChevronLeft, ChevronDown } from 'lucide-react';
|
|
7
|
+
import Tooltip from '../core/Tooltip.js';
|
|
8
|
+
import { useLatestRef } from '../../hooks/useLatestRef.js';
|
|
9
|
+
|
|
10
|
+
var _excluded = ["items", "collapsed", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange"];
|
|
11
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
12
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
13
|
+
// Ctrl/Cmd/Shift/Alt-click or a non-primary button: the browser opens the
|
|
14
|
+
// link in a new tab/window, so the sidebar must not react as if navigating.
|
|
15
|
+
var isModifiedClick = function isModifiedClick(e) {
|
|
16
|
+
return Boolean(e && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || typeof e.button === "number" && e.button !== 0));
|
|
17
|
+
};
|
|
18
|
+
// Focus trap for the mobile drawer (same selector as feedback/Dialog).
|
|
19
|
+
var FOCUSABLE_SELECTOR = ["a[href]", "button:not([disabled])", "textarea:not([disabled])", "input:not([disabled])", "select:not([disabled])", '[tabindex]:not([tabindex="-1"])'].join(",");
|
|
20
|
+
var getFocusable = function getFocusable(root) {
|
|
21
|
+
return root ? Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) {
|
|
22
|
+
return el.getAttribute("aria-hidden") !== "true";
|
|
23
|
+
}) : [];
|
|
24
|
+
};
|
|
25
|
+
var hasChildItems = function hasChildItems(item) {
|
|
26
|
+
return Array.isArray(item.children) && item.children.length > 0;
|
|
27
|
+
};
|
|
28
|
+
// Ids of every parent that must be open for an `active: true` item to be
|
|
29
|
+
// visible (nested included). An active parent is opened too.
|
|
30
|
+
var findActiveAncestors = function findActiveAncestors(list) {
|
|
31
|
+
var ids = [];
|
|
32
|
+
var _walk = function walk(nodes) {
|
|
33
|
+
var containsActive = false;
|
|
34
|
+
nodes.forEach(function (node) {
|
|
35
|
+
if (!node) return;
|
|
36
|
+
var subtreeActive = hasChildItems(node) ? _walk(node.children) : false;
|
|
37
|
+
if (hasChildItems(node) && (subtreeActive || node.active)) ids.push(node.id);
|
|
38
|
+
if (subtreeActive || node.active) containsActive = true;
|
|
39
|
+
});
|
|
40
|
+
return containsActive;
|
|
41
|
+
};
|
|
42
|
+
_walk(Array.isArray(list) ? list : []);
|
|
43
|
+
return ids;
|
|
44
|
+
};
|
|
45
|
+
var mergeIds = function mergeIds(base, extra) {
|
|
46
|
+
var out = _toConsumableArray(base);
|
|
47
|
+
extra.forEach(function (id) {
|
|
48
|
+
if (!out.includes(id)) out.push(id);
|
|
49
|
+
});
|
|
50
|
+
return out;
|
|
51
|
+
};
|
|
52
|
+
// Top-level items grouped by `item.group`, in order of first appearance
|
|
53
|
+
// (same algorithm as AppShell's NavList). Ungrouped items share the "" key.
|
|
54
|
+
var groupItems = function groupItems(list) {
|
|
55
|
+
var groups = [];
|
|
56
|
+
list.forEach(function (item) {
|
|
57
|
+
var key = item.group || "";
|
|
58
|
+
var g = groups.find(function (x) {
|
|
59
|
+
return x.key === key;
|
|
60
|
+
});
|
|
61
|
+
if (!g) groups.push(g = {
|
|
62
|
+
key: key,
|
|
63
|
+
items: []
|
|
64
|
+
});
|
|
65
|
+
g.items.push(item);
|
|
66
|
+
});
|
|
67
|
+
return groups;
|
|
68
|
+
};
|
|
69
|
+
// `0`, "", null, undefined and false render no badge.
|
|
70
|
+
var hasBadge = function hasBadge(item) {
|
|
71
|
+
return item.badge !== undefined && item.badge !== null && item.badge !== false && item.badge !== "" && item.badge !== 0;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Sidebar component with custom tooltip for collapsed mode.
|
|
75
|
+
*
|
|
76
|
+
* Every item (parent or child) renders as an anchor, so items with `href`
|
|
77
|
+
* support Ctrl/Cmd-click, middle-click and "open in new tab".
|
|
78
|
+
*
|
|
79
|
+
* Props:
|
|
80
|
+
* - items: array of { id, label, icon, href?, target?, rel?, children?, onClick?,
|
|
81
|
+
* active?, disabled?, badge?, badgeLabel?, group? }
|
|
82
|
+
* - linkAs: element type used for items with `href` (default "a"; pass Next.js Link etc.)
|
|
83
|
+
* - collapsed: boolean (desktop collapsed)
|
|
84
|
+
* - onToggle: function to toggle collapse
|
|
85
|
+
* - expandedIds / defaultExpandedIds / onExpandedChange: open groups (ids)
|
|
86
|
+
* - className, containerClassName, stickyOffset, logo, footer, user, onUserClick
|
|
87
|
+
* - drawerPosition: 'left' | 'right'
|
|
88
|
+
* - isMobileOpen, setIsMobileOpen
|
|
89
|
+
* - showCollapsedTooltips: boolean (default true)
|
|
90
|
+
*/
|
|
91
|
+
var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
92
|
+
var _ref$items = _ref.items,
|
|
93
|
+
items = _ref$items === void 0 ? [] : _ref$items,
|
|
94
|
+
_ref$collapsed = _ref.collapsed,
|
|
95
|
+
collapsed = _ref$collapsed === void 0 ? false : _ref$collapsed,
|
|
96
|
+
onToggle = _ref.onToggle,
|
|
97
|
+
className = _ref.className,
|
|
98
|
+
containerClassName = _ref.containerClassName,
|
|
99
|
+
stickyOffset = _ref.stickyOffset,
|
|
100
|
+
logo = _ref.logo,
|
|
101
|
+
footer = _ref.footer,
|
|
102
|
+
user = _ref.user,
|
|
103
|
+
onUserClick = _ref.onUserClick,
|
|
104
|
+
_ref$drawerPosition = _ref.drawerPosition,
|
|
105
|
+
drawerPosition = _ref$drawerPosition === void 0 ? "left" : _ref$drawerPosition,
|
|
106
|
+
_ref$isMobileOpen = _ref.isMobileOpen,
|
|
107
|
+
isMobileOpen = _ref$isMobileOpen === void 0 ? false : _ref$isMobileOpen,
|
|
108
|
+
setIsMobileOpen = _ref.setIsMobileOpen,
|
|
109
|
+
_ref$showCollapsedToo = _ref.showCollapsedTooltips,
|
|
110
|
+
showCollapsedTooltips = _ref$showCollapsedToo === void 0 ? true : _ref$showCollapsedToo,
|
|
111
|
+
tooltipOptions = _ref.tooltipOptions,
|
|
112
|
+
_ref$linkAs = _ref.linkAs,
|
|
113
|
+
Link = _ref$linkAs === void 0 ? "a" : _ref$linkAs,
|
|
114
|
+
expandedIds = _ref.expandedIds,
|
|
115
|
+
defaultExpandedIds = _ref.defaultExpandedIds,
|
|
116
|
+
onExpandedChange = _ref.onExpandedChange,
|
|
117
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
118
|
+
// -- expansion (controlled via `expandedIds`, else internal) ----------------
|
|
119
|
+
var isExpansionControlled = expandedIds !== undefined;
|
|
120
|
+
var activeAncestors = useMemo(function () {
|
|
121
|
+
return findActiveAncestors(items);
|
|
122
|
+
}, [items]);
|
|
123
|
+
var activeKey = activeAncestors.join("\0");
|
|
124
|
+
var _useState = useState(function () {
|
|
125
|
+
return mergeIds(Array.isArray(defaultExpandedIds) ? defaultExpandedIds : [], activeAncestors);
|
|
126
|
+
}),
|
|
127
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
128
|
+
internalExpanded = _useState2[0],
|
|
129
|
+
setInternalExpanded = _useState2[1];
|
|
130
|
+
// Open the groups holding a newly-active item (adjust-during-render).
|
|
131
|
+
var _useState3 = useState(activeKey),
|
|
132
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
133
|
+
prevActiveKey = _useState4[0],
|
|
134
|
+
setPrevActiveKey = _useState4[1];
|
|
135
|
+
if (activeKey !== prevActiveKey) {
|
|
136
|
+
setPrevActiveKey(activeKey);
|
|
137
|
+
if (!isExpansionControlled) {
|
|
138
|
+
setInternalExpanded(function (prev) {
|
|
139
|
+
return mergeIds(prev, activeAncestors);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
var expandedList = isExpansionControlled ? Array.isArray(expandedIds) ? expandedIds : [] : internalExpanded;
|
|
144
|
+
var isExpandedId = function isExpandedId(id) {
|
|
145
|
+
return expandedList.includes(id);
|
|
146
|
+
};
|
|
147
|
+
var onExpandedChangeRef = useLatestRef(onExpandedChange);
|
|
148
|
+
var expandedIdsRef = useLatestRef(expandedIds);
|
|
149
|
+
var activeAncestorsRef = useLatestRef(activeAncestors);
|
|
150
|
+
// Controlled: ask the owner to open the groups holding the active item, on
|
|
151
|
+
// mount and whenever the active item moves.
|
|
152
|
+
useEffect(function () {
|
|
153
|
+
var _onExpandedChangeRef$;
|
|
154
|
+
if (!isExpansionControlled) return;
|
|
155
|
+
var current = Array.isArray(expandedIdsRef.current) ? expandedIdsRef.current : [];
|
|
156
|
+
var next = mergeIds(current, activeAncestorsRef.current);
|
|
157
|
+
if (next.length !== current.length) (_onExpandedChangeRef$ = onExpandedChangeRef.current) === null || _onExpandedChangeRef$ === void 0 || _onExpandedChangeRef$.call(onExpandedChangeRef, next);
|
|
158
|
+
}, [activeKey, isExpansionControlled, expandedIdsRef, activeAncestorsRef, onExpandedChangeRef]);
|
|
159
|
+
var setExpanded = function setExpanded(next) {
|
|
160
|
+
if (!isExpansionControlled) setInternalExpanded(next);
|
|
161
|
+
onExpandedChange === null || onExpandedChange === void 0 || onExpandedChange(next);
|
|
162
|
+
};
|
|
163
|
+
var _useState5 = useState(null),
|
|
164
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
165
|
+
activeItemId = _useState6[0],
|
|
166
|
+
setActiveItemId = _useState6[1];
|
|
167
|
+
// Content is rendered twice (desktop pane + mobile drawer), so DOM ids are
|
|
168
|
+
// scoped per instance and per pane.
|
|
169
|
+
var instanceId = useId();
|
|
170
|
+
var drawerRef = useRef(null);
|
|
171
|
+
var setIsMobileOpenRef = useLatestRef(setIsMobileOpen);
|
|
172
|
+
var mobileOpen = isMobileOpen !== null && isMobileOpen !== void 0 ? isMobileOpen : false;
|
|
173
|
+
var effectiveCollapsed = mobileOpen ? false : collapsed;
|
|
174
|
+
useEffect(function () {
|
|
175
|
+
if (mobileOpen) document.body.style.overflow = "hidden";else document.body.style.overflow = "";
|
|
176
|
+
return function () {
|
|
177
|
+
document.body.style.overflow = "";
|
|
178
|
+
};
|
|
179
|
+
}, [mobileOpen]);
|
|
180
|
+
// The drawer stays mounted (it slides in/out), so when it is shut it must
|
|
181
|
+
// leave the tab order and the a11y tree. `inert` is set imperatively: React
|
|
182
|
+
// 18 does not know the attribute and React 19 treats `inert=""` as false.
|
|
183
|
+
useIsomorphicLayoutEffect(function () {
|
|
184
|
+
var drawer = drawerRef.current;
|
|
185
|
+
if (!drawer) return;
|
|
186
|
+
if (mobileOpen) drawer.removeAttribute("inert");else drawer.setAttribute("inert", "");
|
|
187
|
+
}, [mobileOpen]);
|
|
188
|
+
// Open drawer = modal dialog: initial focus inside, Tab trapped, Escape
|
|
189
|
+
// closes, focus returns to the opener on close (WAI-ARIA APG dialog).
|
|
190
|
+
useEffect(function () {
|
|
191
|
+
var _ref2, _ref2$focus, _focusables$;
|
|
192
|
+
if (!mobileOpen) return undefined;
|
|
193
|
+
var drawer = drawerRef.current;
|
|
194
|
+
var previouslyFocused = document.activeElement;
|
|
195
|
+
var focusables = getFocusable(drawer);
|
|
196
|
+
(_ref2 = (_focusables$ = focusables[0]) !== null && _focusables$ !== void 0 ? _focusables$ : drawer) === null || _ref2 === void 0 || (_ref2$focus = _ref2.focus) === null || _ref2$focus === void 0 || _ref2$focus.call(_ref2);
|
|
197
|
+
var handleKeyDown = function handleKeyDown(e) {
|
|
198
|
+
if (e.key === "Escape") {
|
|
199
|
+
var _setIsMobileOpenRef$c;
|
|
200
|
+
(_setIsMobileOpenRef$c = setIsMobileOpenRef.current) === null || _setIsMobileOpenRef$c === void 0 || _setIsMobileOpenRef$c.call(setIsMobileOpenRef, false);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (e.key !== "Tab" || !drawer) return;
|
|
204
|
+
// md+ viewports hide the drawer (md:hidden): nothing to trap.
|
|
205
|
+
if (window.getComputedStyle(drawer).display === "none") return;
|
|
206
|
+
var nodes = getFocusable(drawer);
|
|
207
|
+
if (nodes.length === 0) {
|
|
208
|
+
e.preventDefault();
|
|
209
|
+
drawer.focus();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
var first = nodes[0];
|
|
213
|
+
var last = nodes[nodes.length - 1];
|
|
214
|
+
var active = document.activeElement;
|
|
215
|
+
var outside = !drawer.contains(active) || active === drawer;
|
|
216
|
+
if (e.shiftKey && (active === first || outside)) {
|
|
217
|
+
e.preventDefault();
|
|
218
|
+
last.focus();
|
|
219
|
+
} else if (!e.shiftKey && (active === last || outside)) {
|
|
220
|
+
e.preventDefault();
|
|
221
|
+
first.focus();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
225
|
+
return function () {
|
|
226
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
227
|
+
// Restore focus only if it is still in the drawer (or was dropped to
|
|
228
|
+
// <body> when the drawer went inert) — never steal it from elsewhere.
|
|
229
|
+
var active = document.activeElement;
|
|
230
|
+
var focusLost = !active || active === document.body || (drawer === null || drawer === void 0 ? void 0 : drawer.contains(active));
|
|
231
|
+
if (focusLost && previouslyFocused && previouslyFocused !== document.body && typeof previouslyFocused.focus === "function" && document.contains(previouslyFocused)) {
|
|
232
|
+
previouslyFocused.focus();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}, [mobileOpen, setIsMobileOpenRef]);
|
|
236
|
+
var closeMobile = function closeMobile() {
|
|
237
|
+
if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
|
|
238
|
+
};
|
|
239
|
+
var toggleExpanded = function toggleExpanded(itemId) {
|
|
240
|
+
setExpanded(isExpandedId(itemId) ? expandedList.filter(function (id) {
|
|
241
|
+
return id !== itemId;
|
|
242
|
+
}) : [].concat(_toConsumableArray(expandedList), [itemId]));
|
|
243
|
+
};
|
|
244
|
+
var expandSingle = function expandSingle(itemId) {
|
|
245
|
+
setExpanded([itemId]);
|
|
246
|
+
};
|
|
247
|
+
var handleItemClick = function handleItemClick(item, e) {
|
|
248
|
+
if (item.disabled) {
|
|
249
|
+
e === null || e === void 0 || e.preventDefault();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// Let the browser handle new-tab / new-window clicks untouched.
|
|
253
|
+
if (item.href && isModifiedClick(e)) return;
|
|
254
|
+
var hasChildren = hasChildItems(item);
|
|
255
|
+
if (hasChildren && effectiveCollapsed && !mobileOpen) {
|
|
256
|
+
// ask parent to uncollapse
|
|
257
|
+
onToggle === null || onToggle === void 0 || onToggle();
|
|
258
|
+
setActiveItemId(item.id);
|
|
259
|
+
expandSingle(item.id);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (hasChildren) {
|
|
263
|
+
// A parent with an href navigates, so keep its group open rather than
|
|
264
|
+
// collapsing it on the way out; the chevron is the collapse control.
|
|
265
|
+
if (item.href) {
|
|
266
|
+
if (!isExpandedId(item.id)) toggleExpanded(item.id);
|
|
267
|
+
closeMobile();
|
|
268
|
+
} else {
|
|
269
|
+
toggleExpanded(item.id);
|
|
270
|
+
}
|
|
271
|
+
setActiveItemId(item.id);
|
|
272
|
+
} else {
|
|
273
|
+
var _item$onClick;
|
|
274
|
+
(_item$onClick = item.onClick) === null || _item$onClick === void 0 || _item$onClick.call(item, item);
|
|
275
|
+
setActiveItemId(item.id);
|
|
276
|
+
closeMobile();
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
// Chevron on a parent link: toggle the group without following the link.
|
|
280
|
+
var handleChevronClick = function handleChevronClick(item, e) {
|
|
281
|
+
e.preventDefault();
|
|
282
|
+
e.stopPropagation();
|
|
283
|
+
if (item.disabled) return;
|
|
284
|
+
toggleExpanded(item.id);
|
|
285
|
+
};
|
|
286
|
+
var handleUserClick = function handleUserClick() {
|
|
287
|
+
onUserClick === null || onUserClick === void 0 || onUserClick(user);
|
|
288
|
+
closeMobile();
|
|
289
|
+
};
|
|
290
|
+
var _renderMenuItem = function renderMenuItem(item, level, pane) {
|
|
291
|
+
var _item$badgeLabel, _item$rel;
|
|
292
|
+
var hasChildren = hasChildItems(item);
|
|
293
|
+
var isExpanded = isExpandedId(item.id);
|
|
294
|
+
var isActive = Boolean(item.active) || activeItemId === item.id;
|
|
295
|
+
var showTooltipForThis = effectiveCollapsed && level === 0 && showCollapsedTooltips;
|
|
296
|
+
var labelHidden = effectiveCollapsed && level === 0;
|
|
297
|
+
var hasHref = Boolean(item.href) && !item.disabled;
|
|
298
|
+
var ItemTag = hasHref ? Link : "a";
|
|
299
|
+
var groupId = hasChildren ? "".concat(instanceId, "-").concat(pane, "-group-").concat(item.id) : undefined;
|
|
300
|
+
var showBadge = hasBadge(item);
|
|
301
|
+
var badgeText = showBadge ? String((_item$badgeLabel = item.badgeLabel) !== null && _item$badgeLabel !== void 0 ? _item$badgeLabel : item.badge) : undefined;
|
|
302
|
+
// Collapsed: the badge shrinks onto the icon.
|
|
303
|
+
var compactBadge = showBadge && labelHidden && jsx("span", {
|
|
304
|
+
className: "absolute -right-2 -top-1.5 min-w-4 rounded-full bg-primary-600 px-1 text-center text-micro font-semibold text-white",
|
|
305
|
+
"aria-hidden": "true",
|
|
306
|
+
"data-sidebar-badge": "compact",
|
|
307
|
+
children: item.badge
|
|
308
|
+
});
|
|
309
|
+
var iconEl = item.icon ? jsxs("span", {
|
|
310
|
+
className: cn("relative flex-shrink-0", {
|
|
311
|
+
"mr-3": !labelHidden,
|
|
312
|
+
"mr-0": labelHidden
|
|
313
|
+
}),
|
|
314
|
+
"aria-hidden": "true",
|
|
315
|
+
children: [item.icon, compactBadge]
|
|
316
|
+
}) : compactBadge && jsx("span", {
|
|
317
|
+
className: "relative h-4 w-0",
|
|
318
|
+
children: compactBadge
|
|
319
|
+
});
|
|
320
|
+
var itemEl = jsxs(ItemTag, _objectSpread2(_objectSpread2({}, hasHref ? {
|
|
321
|
+
href: item.href,
|
|
322
|
+
target: item.target,
|
|
323
|
+
rel: (_item$rel = item.rel) !== null && _item$rel !== void 0 ? _item$rel : item.target === "_blank" ? "noopener noreferrer" : undefined,
|
|
324
|
+
"aria-current": isActive ? "page" : undefined
|
|
325
|
+
} : {
|
|
326
|
+
// No destination: behave as a button, keyboard included.
|
|
327
|
+
role: "button",
|
|
328
|
+
tabIndex: item.disabled ? -1 : 0,
|
|
329
|
+
onKeyDown: function onKeyDown(e) {
|
|
330
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
331
|
+
e.preventDefault();
|
|
332
|
+
handleItemClick(item, e);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}), {}, {
|
|
336
|
+
className: cn("flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", {
|
|
337
|
+
"bg-primary-100 text-primary-700": isActive,
|
|
338
|
+
"hover:bg-gray-100": !isActive && !item.disabled,
|
|
339
|
+
"cursor-pointer": !item.disabled,
|
|
340
|
+
"cursor-not-allowed opacity-50": item.disabled,
|
|
341
|
+
"justify-center": labelHidden
|
|
342
|
+
}),
|
|
343
|
+
onClick: function onClick(e) {
|
|
344
|
+
return handleItemClick(item, e);
|
|
345
|
+
},
|
|
346
|
+
"aria-label": labelHidden ? showBadge ? "".concat(item.label, ", ").concat(badgeText) : item.label : undefined,
|
|
347
|
+
"aria-expanded": hasChildren ? isExpanded : undefined,
|
|
348
|
+
"aria-controls": hasChildren && isExpanded ? groupId : undefined,
|
|
349
|
+
"aria-disabled": item.disabled || undefined,
|
|
350
|
+
children: [iconEl, !labelHidden && jsxs(Fragment, {
|
|
351
|
+
children: [jsx("span", {
|
|
352
|
+
className: "flex-1 truncate",
|
|
353
|
+
children: item.label
|
|
354
|
+
}), showBadge && jsx("span", {
|
|
355
|
+
className: "ml-2 flex-shrink-0 rounded-full bg-primary-600 px-2 py-0.5 text-xs font-semibold leading-none text-white",
|
|
356
|
+
"data-sidebar-badge": "",
|
|
357
|
+
children: item.badgeLabel != null ? jsxs(Fragment, {
|
|
358
|
+
children: [jsx("span", {
|
|
359
|
+
"aria-hidden": "true",
|
|
360
|
+
children: item.badge
|
|
361
|
+
}), jsx("span", {
|
|
362
|
+
className: "sr-only",
|
|
363
|
+
children: item.badgeLabel
|
|
364
|
+
})]
|
|
365
|
+
}) : item.badge
|
|
366
|
+
}), hasChildren && jsx("span", {
|
|
367
|
+
className: "ml-2 flex-shrink-0 rounded p-0.5 hover:bg-gray-200",
|
|
368
|
+
"aria-hidden": "true",
|
|
369
|
+
"data-sidebar-chevron": "",
|
|
370
|
+
onClick: hasHref ? function (e) {
|
|
371
|
+
return handleChevronClick(item, e);
|
|
372
|
+
} : undefined,
|
|
373
|
+
children: isExpanded ? jsx(ChevronDown, {
|
|
374
|
+
className: "h-4 w-4"
|
|
375
|
+
}) : jsx(ChevronRight, {
|
|
376
|
+
className: "h-4 w-4"
|
|
377
|
+
})
|
|
378
|
+
})]
|
|
379
|
+
})]
|
|
380
|
+
}));
|
|
381
|
+
return jsxs("div", {
|
|
382
|
+
className: "relative",
|
|
383
|
+
children: [showTooltipForThis ? jsx(Tooltip, _objectSpread2(_objectSpread2({}, tooltipOptions), {}, {
|
|
384
|
+
trigger: "hover",
|
|
385
|
+
content: item.label,
|
|
386
|
+
position: "right",
|
|
387
|
+
customTrigger: itemEl
|
|
388
|
+
})) : itemEl, hasChildren && isExpanded && (!effectiveCollapsed || level > 0) && jsx("div", {
|
|
389
|
+
id: groupId,
|
|
390
|
+
className: "mt-1 space-y-1 ml-2",
|
|
391
|
+
children: item.children.map(function (child) {
|
|
392
|
+
return _renderMenuItem(child, level + 1, pane);
|
|
393
|
+
})
|
|
394
|
+
})]
|
|
395
|
+
}, item.id);
|
|
396
|
+
};
|
|
397
|
+
// Section headings (items with `group`). Collapsed: the heading becomes a
|
|
398
|
+
// divider and stays available to screen readers.
|
|
399
|
+
var renderNavContent = function renderNavContent(pane) {
|
|
400
|
+
if (!items.some(function (item) {
|
|
401
|
+
return item && item.group;
|
|
402
|
+
})) {
|
|
403
|
+
return items.map(function (item) {
|
|
404
|
+
return _renderMenuItem(item, 0, pane);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
return groupItems(items).map(function (section, idx) {
|
|
408
|
+
var headingId = "".concat(instanceId, "-").concat(pane, "-section-").concat(idx);
|
|
409
|
+
return jsxs("div", {
|
|
410
|
+
role: section.key ? "group" : undefined,
|
|
411
|
+
"aria-labelledby": section.key ? headingId : undefined,
|
|
412
|
+
className: cn("space-y-1", {
|
|
413
|
+
"pt-3": idx > 0 && !effectiveCollapsed
|
|
414
|
+
}),
|
|
415
|
+
"data-sidebar-section": section.key || "",
|
|
416
|
+
children: [effectiveCollapsed && idx > 0 && jsx("hr", {
|
|
417
|
+
className: "mx-2 my-2 border-gray-200",
|
|
418
|
+
"aria-hidden": "true"
|
|
419
|
+
}), section.key && (effectiveCollapsed ? jsx("span", {
|
|
420
|
+
id: headingId,
|
|
421
|
+
className: "sr-only",
|
|
422
|
+
children: section.key
|
|
423
|
+
}) : jsx("p", {
|
|
424
|
+
id: headingId,
|
|
425
|
+
className: "px-3 pb-1 pt-2 text-micro font-semibold uppercase tracking-wide text-gray-500",
|
|
426
|
+
children: section.key
|
|
427
|
+
})), section.items.map(function (item) {
|
|
428
|
+
return _renderMenuItem(item, 0, pane);
|
|
429
|
+
})]
|
|
430
|
+
}, section.key || "__ungrouped");
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
var handleToggleClick = function handleToggleClick() {
|
|
434
|
+
if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);else onToggle === null || onToggle === void 0 || onToggle();
|
|
435
|
+
};
|
|
436
|
+
var renderUserBlock = function renderUserBlock() {
|
|
437
|
+
var content = jsxs(Fragment, {
|
|
438
|
+
children: [user.avatar && jsx("img", {
|
|
439
|
+
src: user.avatar,
|
|
440
|
+
alt: user.name,
|
|
441
|
+
className: "h-8 w-8 rounded-full flex-shrink-0"
|
|
442
|
+
}), !effectiveCollapsed && jsxs("span", {
|
|
443
|
+
className: "ml-3 block min-w-0 flex-1",
|
|
444
|
+
children: [jsx("span", {
|
|
445
|
+
className: "block text-sm font-medium truncate",
|
|
446
|
+
children: user.name
|
|
447
|
+
}), jsx("span", {
|
|
448
|
+
className: "block text-xs text-primary-500 truncate",
|
|
449
|
+
children: user.email
|
|
450
|
+
})]
|
|
451
|
+
})]
|
|
452
|
+
});
|
|
453
|
+
var base = cn("flex w-full items-center rounded-md px-3 py-2 text-left", {
|
|
454
|
+
"justify-center": effectiveCollapsed,
|
|
455
|
+
"p-2": effectiveCollapsed
|
|
456
|
+
});
|
|
457
|
+
if (!onUserClick) return jsx("div", {
|
|
458
|
+
className: base,
|
|
459
|
+
children: content
|
|
460
|
+
});
|
|
461
|
+
return jsx("button", {
|
|
462
|
+
type: "button",
|
|
463
|
+
onClick: handleUserClick,
|
|
464
|
+
className: cn(base, "cursor-pointer hover:bg-gray-100 transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"),
|
|
465
|
+
"aria-label": effectiveCollapsed && !user.avatar ? user.name : undefined,
|
|
466
|
+
children: content
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
var renderFooter = function renderFooter(pane) {
|
|
470
|
+
if (footer === undefined || footer === null || footer === false) return null;
|
|
471
|
+
var content = typeof footer === "function" ? footer({
|
|
472
|
+
collapsed: effectiveCollapsed,
|
|
473
|
+
isMobile: pane === "mobile",
|
|
474
|
+
closeMobile: closeMobile
|
|
475
|
+
}) : footer;
|
|
476
|
+
if (content === undefined || content === null || content === false) return null;
|
|
477
|
+
return jsx("div", {
|
|
478
|
+
className: "border-t border-gray-200 p-4",
|
|
479
|
+
"data-sidebar-footer": "",
|
|
480
|
+
children: content
|
|
481
|
+
});
|
|
482
|
+
};
|
|
483
|
+
var renderSidebarContent = function renderSidebarContent(pane) {
|
|
484
|
+
return jsxs("div", {
|
|
485
|
+
className: cn("flex h-full flex-col bg-white border-r border-gray-200 shadow-sm", "w-64 transition-all duration-200", {
|
|
486
|
+
"w-16": effectiveCollapsed,
|
|
487
|
+
"w-64": !effectiveCollapsed
|
|
488
|
+
}),
|
|
489
|
+
children: [jsxs("div", {
|
|
490
|
+
className: "flex h-16 items-center justify-between border-b border-gray-200 px-4",
|
|
491
|
+
children: [!effectiveCollapsed && logo && jsx("div", {
|
|
492
|
+
className: "flex items-center",
|
|
493
|
+
children: logo
|
|
494
|
+
}), jsx("button", {
|
|
495
|
+
type: "button",
|
|
496
|
+
onClick: handleToggleClick,
|
|
497
|
+
className: "rounded-md p-1 hover:bg-gray-100",
|
|
498
|
+
"aria-label": effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
499
|
+
children: effectiveCollapsed ? jsx(ChevronRight, {
|
|
500
|
+
className: "h-5 w-5"
|
|
501
|
+
}) : jsx(ChevronLeft, {
|
|
502
|
+
className: "h-5 w-5"
|
|
503
|
+
})
|
|
504
|
+
})]
|
|
505
|
+
}), jsx("nav", {
|
|
506
|
+
className: "flex-1 space-y-1 overflow-y-auto p-4 [&::-webkit-scrollbar]:w-2\n [&::-webkit-scrollbar-track]:bg-gray-100\n [&::-webkit-scrollbar-thumb]:bg-gray-300\n hover:[&::-webkit-scrollbar-thumb]:bg-gray-400",
|
|
507
|
+
children: renderNavContent(pane)
|
|
508
|
+
}), renderFooter(pane), user && jsx("div", {
|
|
509
|
+
className: "border-t border-gray-200 p-4",
|
|
510
|
+
children: jsx("div", {
|
|
511
|
+
className: "relative",
|
|
512
|
+
children: renderUserBlock()
|
|
513
|
+
})
|
|
514
|
+
})]
|
|
515
|
+
});
|
|
516
|
+
};
|
|
517
|
+
var isRight = drawerPosition === "right";
|
|
518
|
+
var mobileDrawerClasses = cn("fixed top-0 z-50 h-full transition-transform duration-300 ease-in-out motion-reduce:transition-none md:hidden", {
|
|
519
|
+
"left-0": !isRight,
|
|
520
|
+
"right-0": isRight
|
|
521
|
+
}, {
|
|
522
|
+
"translate-x-0": mobileOpen,
|
|
523
|
+
"-translate-x-full": !mobileOpen && !isRight,
|
|
524
|
+
"translate-x-full": !mobileOpen && isRight
|
|
525
|
+
});
|
|
526
|
+
var desktopPlacementClass = isRight ? "md:order-last" : "";
|
|
527
|
+
// A top bar above the sidebar: stick below it and shrink to fit.
|
|
528
|
+
var offset = typeof stickyOffset === "number" ? "".concat(stickyOffset, "px") : stickyOffset;
|
|
529
|
+
var containerStyle = offset ? {
|
|
530
|
+
top: offset,
|
|
531
|
+
height: "calc(100dvh - ".concat(offset, ")")
|
|
532
|
+
} : undefined;
|
|
533
|
+
return jsxs(Fragment, {
|
|
534
|
+
children: [jsx("div", {
|
|
535
|
+
className: cn("hidden md:flex sticky top-0 h-screen", containerClassName),
|
|
536
|
+
style: containerStyle,
|
|
537
|
+
"data-sidebar-container": "",
|
|
538
|
+
children: jsx("div", _objectSpread2(_objectSpread2({
|
|
539
|
+
ref: ref,
|
|
540
|
+
className: cn(desktopPlacementClass, className)
|
|
541
|
+
}, props), {}, {
|
|
542
|
+
children: renderSidebarContent("desktop")
|
|
543
|
+
}))
|
|
544
|
+
}), mobileOpen && jsx("div", {
|
|
545
|
+
className: "fixed inset-0 bg-black/30 z-40 md:hidden",
|
|
546
|
+
onClick: function onClick() {
|
|
547
|
+
return setIsMobileOpen === null || setIsMobileOpen === void 0 ? void 0 : setIsMobileOpen(false);
|
|
548
|
+
},
|
|
549
|
+
"aria-hidden": "true"
|
|
550
|
+
}), jsx("aside", {
|
|
551
|
+
ref: drawerRef,
|
|
552
|
+
className: mobileDrawerClasses,
|
|
553
|
+
role: "dialog",
|
|
554
|
+
"aria-modal": "true",
|
|
555
|
+
"aria-label": "Navigation",
|
|
556
|
+
"aria-hidden": mobileOpen ? undefined : true,
|
|
557
|
+
tabIndex: -1,
|
|
558
|
+
style: {
|
|
559
|
+
zIndex: 50
|
|
560
|
+
},
|
|
561
|
+
children: renderSidebarContent("mobile")
|
|
562
|
+
})]
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
Sidebar.displayName = "Sidebar";
|
|
566
|
+
|
|
567
|
+
export { Sidebar as default };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { User } from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
var _excluded = ["src", "alt", "name", "size", "shape", "status", "className"];
|
|
9
|
+
var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
10
|
+
var src = _ref.src,
|
|
11
|
+
alt = _ref.alt,
|
|
12
|
+
name = _ref.name,
|
|
13
|
+
_ref$size = _ref.size,
|
|
14
|
+
size = _ref$size === void 0 ? 'md' : _ref$size,
|
|
15
|
+
_ref$shape = _ref.shape,
|
|
16
|
+
shape = _ref$shape === void 0 ? 'circle' : _ref$shape,
|
|
17
|
+
status = _ref.status,
|
|
18
|
+
className = _ref.className,
|
|
19
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
20
|
+
var sizes = {
|
|
21
|
+
xs: 'h-6 w-6 text-xs',
|
|
22
|
+
sm: 'h-8 w-8 text-sm',
|
|
23
|
+
md: 'h-10 w-10 text-base',
|
|
24
|
+
lg: 'h-12 w-12 text-lg',
|
|
25
|
+
xl: 'h-16 w-16 text-xl',
|
|
26
|
+
'2xl': 'h-20 w-20 text-2xl'
|
|
27
|
+
};
|
|
28
|
+
var getInitials = function getInitials(name) {
|
|
29
|
+
if (!name) return '';
|
|
30
|
+
return name.split(' ').map(function (word) {
|
|
31
|
+
return word.charAt(0);
|
|
32
|
+
}).join('').toUpperCase().slice(0, 2);
|
|
33
|
+
};
|
|
34
|
+
var statusColors = {
|
|
35
|
+
online: 'bg-success-500',
|
|
36
|
+
offline: 'bg-gray-400',
|
|
37
|
+
away: 'bg-warning-500',
|
|
38
|
+
busy: 'bg-error-500'
|
|
39
|
+
};
|
|
40
|
+
var statusSizes = {
|
|
41
|
+
xs: 'h-1.5 w-1.5',
|
|
42
|
+
sm: 'h-2 w-2',
|
|
43
|
+
md: 'h-2.5 w-2.5',
|
|
44
|
+
lg: 'h-3 w-3',
|
|
45
|
+
xl: 'h-4 w-4',
|
|
46
|
+
'2xl': 'h-5 w-5'
|
|
47
|
+
};
|
|
48
|
+
return jsxs("div", {
|
|
49
|
+
ref: ref,
|
|
50
|
+
className: "relative inline-block",
|
|
51
|
+
children: [jsxs("div", _objectSpread2(_objectSpread2({
|
|
52
|
+
className: cn('flex items-center justify-center bg-gray-100 text-primary-600 font-medium', sizes[size], {
|
|
53
|
+
'rounded-full': shape === 'circle',
|
|
54
|
+
'rounded-md': shape === 'square',
|
|
55
|
+
'rounded-lg': shape === 'rounded'
|
|
56
|
+
}, className)
|
|
57
|
+
}, props), {}, {
|
|
58
|
+
children: [src ? jsx("img", {
|
|
59
|
+
src: src,
|
|
60
|
+
alt: alt || name,
|
|
61
|
+
className: cn('h-full w-full object-cover', {
|
|
62
|
+
'rounded-full': shape === 'circle',
|
|
63
|
+
'rounded-md': shape === 'square',
|
|
64
|
+
'rounded-lg': shape === 'rounded'
|
|
65
|
+
}),
|
|
66
|
+
onError: function onError(e) {
|
|
67
|
+
e.target.style.display = 'none';
|
|
68
|
+
e.target.nextSibling.style.display = 'flex';
|
|
69
|
+
}
|
|
70
|
+
}) : null, jsx("div", {
|
|
71
|
+
className: cn('flex items-center justify-center h-full w-full', {
|
|
72
|
+
'rounded-full': shape === 'circle',
|
|
73
|
+
'rounded-md': shape === 'square',
|
|
74
|
+
'rounded-lg': shape === 'rounded'
|
|
75
|
+
}, {
|
|
76
|
+
'hidden': src
|
|
77
|
+
}),
|
|
78
|
+
children: name ? getInitials(name) : jsx(User, {
|
|
79
|
+
className: "h-1/2 w-1/2"
|
|
80
|
+
})
|
|
81
|
+
})]
|
|
82
|
+
})), status && jsx("span", {
|
|
83
|
+
className: cn('absolute bottom-0 right-0 rounded-full border-2 border-white', statusColors[status], statusSizes[size])
|
|
84
|
+
})]
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
Avatar.displayName = 'Avatar';
|
|
88
|
+
|
|
89
|
+
export { Avatar as default };
|