@dreamtree-org/twreact-ui 1.3.9 → 1.3.11
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/README.md +32 -0
- package/ai-skills/dreamtree-ui.md +12 -7
- package/dist/ai-schema.json +156 -29
- package/dist/charts/index.js +195 -66
- package/dist/components/blocks/AppShell.d.ts.map +1 -1
- package/dist/components/charts/CartesianChart.d.ts.map +1 -1
- package/dist/components/charts/ChartFrame.d.ts.map +1 -1
- package/dist/components/charts/useChartLayout.d.ts +25 -0
- package/dist/components/charts/useChartLayout.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/Form.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/Loader.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/PriceRangePicker.d.ts +0 -29
- 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/RoundedTag.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts.map +1 -1
- 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/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/Pagination.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Table/helpers.d.ts +2 -0
- package/dist/components/core/Table/helpers.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts +2 -5
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/TextToSpeech.d.ts +2 -7
- package/dist/components/core/TextToSpeech.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Alert.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/utility/Avatar.d.ts +8 -0
- package/dist/components/utility/Avatar.d.ts.map +1 -1
- package/dist/components/utility/AvatarGroup.d.ts +4 -0
- package/dist/components/utility/AvatarGroup.d.ts.map +1 -0
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/Card.d.ts.map +1 -1
- package/dist/components/utility/Carousel.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Pagination.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts.map +1 -1
- package/dist/components/utility/Stepper.d.ts.map +1 -1
- package/dist/esm/components/blocks/AppShell.js +24 -18
- package/dist/esm/components/blocks/EmptyState.js +1 -1
- package/dist/esm/components/blocks/ErrorState.js +1 -1
- package/dist/esm/components/blocks/LoadingState.js +4 -4
- package/dist/esm/components/blocks/StatCard.js +6 -6
- package/dist/esm/components/blocks/StatusPill.js +5 -8
- package/dist/esm/components/charts/CartesianChart.js +85 -62
- package/dist/esm/components/charts/ChartFrame.js +12 -5
- package/dist/esm/components/charts/useChartLayout.js +105 -0
- package/dist/esm/components/core/Accordion.js +40 -9
- package/dist/esm/components/core/Button.js +49 -25
- package/dist/esm/components/core/Checkbox.js +71 -45
- package/dist/esm/components/core/ColorPicker.js +49 -48
- package/dist/esm/components/core/DatePicker.js +97 -58
- package/dist/esm/components/core/Form.js +35 -8
- package/dist/esm/components/core/Input.js +89 -20
- package/dist/esm/components/core/Loader.js +30 -44
- package/dist/esm/components/core/LocationPicker.js +82 -16
- package/dist/esm/components/core/PriceRangePicker.js +205 -218
- package/dist/esm/components/core/ProgressBar.js +8 -12
- package/dist/esm/components/core/Radio.js +43 -15
- package/dist/esm/components/core/Rate.js +109 -50
- package/dist/esm/components/core/RoundedTag.js +27 -10
- package/dist/esm/components/core/Skeleton.js +13 -14
- package/dist/esm/components/core/Slider.js +24 -6
- package/dist/esm/components/core/SpeechToText.js +68 -16
- package/dist/esm/components/core/Switch.js +88 -16
- package/dist/esm/components/core/Table/ColumnMenu.js +2 -4
- package/dist/esm/components/core/Table/Pagination.js +15 -18
- package/dist/esm/components/core/Table/TableRow.js +2 -2
- package/dist/esm/components/core/Table/helpers.js +33 -1
- package/dist/esm/components/core/Tabs.js +185 -37
- package/dist/esm/components/core/TextToSpeech.js +121 -28
- package/dist/esm/components/core/Textarea.js +10 -2
- package/dist/esm/components/core/Tooltip.js +100 -28
- package/dist/esm/components/feedback/Alert.js +21 -11
- package/dist/esm/components/feedback/Dialog.js +44 -100
- package/dist/esm/components/feedback/Toast.js +24 -5
- package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
- package/dist/esm/components/navigation/FootNav.js +102 -13
- package/dist/esm/components/navigation/Sidebar.js +13 -61
- package/dist/esm/components/utility/Avatar.js +37 -22
- package/dist/esm/components/utility/AvatarGroup.js +56 -0
- package/dist/esm/components/utility/Badge.js +43 -23
- package/dist/esm/components/utility/Card.js +32 -8
- package/dist/esm/components/utility/Carousel.js +165 -38
- package/dist/esm/components/utility/FileUpload.js +106 -31
- package/dist/esm/components/utility/Pagination.js +33 -15
- package/dist/esm/components/utility/Sortable.js +6 -2
- package/dist/esm/components/utility/Stepper.js +110 -47
- package/dist/esm/hooks/useFocusTrap.js +10 -2
- package/dist/esm/hooks/useSliderValues.js +8 -2
- package/dist/esm/hooks/useSortable.js +107 -5
- package/dist/esm/index.js +1 -0
- package/dist/esm/utils/touchTarget.js +4 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useSliderValues.d.ts +6 -2
- package/dist/hooks/useSliderValues.d.ts.map +1 -1
- package/dist/hooks/useSortable.d.ts +11 -1
- package/dist/hooks/useSortable.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +3734 -2174
- package/dist/index.js +3732 -2171
- package/dist/types/charts.d.ts +3 -1
- package/dist/types/charts.d.ts.map +1 -1
- package/dist/types/index.d.ts +64 -9
- package/dist/types/index.d.ts.map +1 -1
- package/doc/README.md +1 -0
- package/mcp/catalog.snapshot.json +350 -121
- package/package.json +1 -1
|
@@ -1,32 +1,60 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { objectWithoutProperties as _objectWithoutProperties, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import React from 'react';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
6
7
|
import { ChevronRight, Home } from 'lucide-react';
|
|
7
8
|
|
|
8
|
-
var _excluded = ["items", "separator", "showHome", "homeIcon", "onHomeClick", "className"];
|
|
9
|
+
var _excluded = ["items", "separator", "showHome", "homeIcon", "onHomeClick", "maxItems", "className"];
|
|
9
10
|
// Items without an `id` still need a stable, unique React key.
|
|
10
11
|
var itemKey = function itemKey(item, index) {
|
|
11
12
|
var _ref, _item$href;
|
|
12
13
|
return item.id != null ? "id:".concat(item.id) : "idx:".concat(index, ":").concat((_ref = (_item$href = item.href) !== null && _item$href !== void 0 ? _item$href : item.label) !== null && _ref !== void 0 ? _ref : '');
|
|
13
14
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
// Long labels truncate with an ellipsis; the full text stays available as a tooltip.
|
|
16
|
+
var LABEL_CLASSES = 'min-w-0 max-w-[10rem] truncate sm:max-w-[16rem]';
|
|
17
|
+
var FOCUS_RING = 'rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-gray-900';
|
|
18
|
+
var labelTitle = function labelTitle(label) {
|
|
19
|
+
return typeof label === 'string' || typeof label === 'number' ? String(label) : undefined;
|
|
20
|
+
};
|
|
21
|
+
function ItemContent(_ref2) {
|
|
22
|
+
var item = _ref2.item;
|
|
23
|
+
return jsxs(Fragment, {
|
|
24
|
+
children: [item.icon && jsx("span", {
|
|
25
|
+
className: "mr-1 shrink-0",
|
|
26
|
+
children: item.icon
|
|
27
|
+
}), jsx("span", {
|
|
28
|
+
className: LABEL_CLASSES,
|
|
29
|
+
title: labelTitle(item.label),
|
|
30
|
+
children: item.label
|
|
31
|
+
})]
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
var Breadcrumbs = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
35
|
+
var _ref3$items = _ref3.items,
|
|
36
|
+
items = _ref3$items === void 0 ? [] : _ref3$items,
|
|
37
|
+
_ref3$separator = _ref3.separator,
|
|
38
|
+
separator = _ref3$separator === void 0 ? jsx(ChevronRight, {
|
|
19
39
|
className: "h-4 w-4"
|
|
20
|
-
}) :
|
|
21
|
-
|
|
22
|
-
showHome =
|
|
23
|
-
|
|
24
|
-
homeIcon =
|
|
40
|
+
}) : _ref3$separator,
|
|
41
|
+
_ref3$showHome = _ref3.showHome,
|
|
42
|
+
showHome = _ref3$showHome === void 0 ? true : _ref3$showHome,
|
|
43
|
+
_ref3$homeIcon = _ref3.homeIcon,
|
|
44
|
+
homeIcon = _ref3$homeIcon === void 0 ? jsx(Home, {
|
|
25
45
|
className: "h-4 w-4"
|
|
26
|
-
}) :
|
|
27
|
-
onHomeClick =
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
}) : _ref3$homeIcon,
|
|
47
|
+
onHomeClick = _ref3.onHomeClick,
|
|
48
|
+
maxItems = _ref3.maxItems,
|
|
49
|
+
className = _ref3.className,
|
|
50
|
+
props = _objectWithoutProperties(_ref3, _excluded);
|
|
51
|
+
var _useState = useState(false),
|
|
52
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
53
|
+
expanded = _useState2[0],
|
|
54
|
+
setExpanded = _useState2[1];
|
|
55
|
+
// After expanding, focus moves to the first revealed crumb instead of being lost.
|
|
56
|
+
var focusRevealed = useRef(false);
|
|
57
|
+
var firstHiddenRef = useRef(null);
|
|
30
58
|
var allItems = showHome ? [{
|
|
31
59
|
id: 'home',
|
|
32
60
|
label: 'Home',
|
|
@@ -34,37 +62,71 @@ var Breadcrumbs = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
34
62
|
icon: homeIcon,
|
|
35
63
|
onClick: onHomeClick
|
|
36
64
|
}].concat(_toConsumableArray(items)) : items;
|
|
65
|
+
// Collapse keeps the first crumb and the last (maxItems - 1); needs at least 2 to make sense.
|
|
66
|
+
var limit = Number.isFinite(maxItems) ? Math.max(2, Math.floor(maxItems)) : Infinity;
|
|
67
|
+
var collapsed = !expanded && allItems.length > limit;
|
|
68
|
+
var hiddenFrom = 1;
|
|
69
|
+
var hiddenTo = allItems.length - (limit - 1); // exclusive
|
|
70
|
+
var hiddenCount = collapsed ? hiddenTo - hiddenFrom : 0;
|
|
71
|
+
useEffect(function () {
|
|
72
|
+
if (expanded && focusRevealed.current) {
|
|
73
|
+
var _firstHiddenRef$curre;
|
|
74
|
+
focusRevealed.current = false;
|
|
75
|
+
(_firstHiddenRef$curre = firstHiddenRef.current) === null || _firstHiddenRef$curre === void 0 || _firstHiddenRef$curre.focus();
|
|
76
|
+
}
|
|
77
|
+
}, [expanded]);
|
|
78
|
+
var renderSeparator = function renderSeparator() {
|
|
79
|
+
return jsx("span", {
|
|
80
|
+
className: "shrink-0 text-primary-400 dark:text-primary-500",
|
|
81
|
+
"aria-hidden": "true",
|
|
82
|
+
children: separator
|
|
83
|
+
});
|
|
84
|
+
};
|
|
37
85
|
return jsx("nav", _objectSpread2(_objectSpread2({
|
|
38
86
|
ref: ref,
|
|
39
|
-
className: cn('flex items-center space-x-1 text-sm', className),
|
|
87
|
+
className: cn('flex min-w-0 items-center space-x-1 text-sm', className),
|
|
40
88
|
"aria-label": "Breadcrumb"
|
|
41
89
|
}, props), {}, {
|
|
42
90
|
children: allItems.map(function (item, index) {
|
|
91
|
+
if (collapsed && index >= hiddenFrom && index < hiddenTo) {
|
|
92
|
+
if (index !== hiddenFrom) return null;
|
|
93
|
+
return jsxs(React.Fragment, {
|
|
94
|
+
children: [renderSeparator(), jsx("button", {
|
|
95
|
+
type: "button",
|
|
96
|
+
className: cn('inline-flex items-center justify-center px-1 text-primary-500 transition-colors duration-fast motion-reduce:transition-none', 'hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300', FOCUS_RING, TOUCH_TARGET),
|
|
97
|
+
"aria-label": "Show ".concat(hiddenCount, " more breadcrumb").concat(hiddenCount === 1 ? '' : 's'),
|
|
98
|
+
onClick: function onClick() {
|
|
99
|
+
focusRevealed.current = true;
|
|
100
|
+
setExpanded(true);
|
|
101
|
+
},
|
|
102
|
+
children: jsx("span", {
|
|
103
|
+
"aria-hidden": "true",
|
|
104
|
+
children: "\u2026"
|
|
105
|
+
})
|
|
106
|
+
})]
|
|
107
|
+
}, "breadcrumbs-collapsed");
|
|
108
|
+
}
|
|
109
|
+
var isLast = index === allItems.length - 1;
|
|
43
110
|
return jsxs(React.Fragment, {
|
|
44
|
-
children: [index > 0 && jsx("span", {
|
|
45
|
-
className: "text-primary-
|
|
46
|
-
"aria-hidden": "true",
|
|
47
|
-
children: separator
|
|
48
|
-
}), index === allItems.length - 1 ? jsxs("span", {
|
|
49
|
-
className: "font-medium text-primary-900",
|
|
111
|
+
children: [index > 0 && renderSeparator(), isLast ? jsx("span", {
|
|
112
|
+
className: "flex min-w-0 items-center font-medium text-primary-900 dark:text-primary-100",
|
|
50
113
|
"aria-current": "page",
|
|
51
|
-
children:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
114
|
+
children: jsx(ItemContent, {
|
|
115
|
+
item: item
|
|
116
|
+
})
|
|
117
|
+
}) : jsx("a", {
|
|
118
|
+
ref: expanded && index === hiddenFrom ? firstHiddenRef : undefined,
|
|
56
119
|
href: item.href,
|
|
57
|
-
className:
|
|
120
|
+
className: cn('flex min-w-0 items-center text-primary-500 underline-offset-4 transition-colors duration-fast motion-reduce:transition-none', 'hover:text-primary-700 hover:underline dark:text-primary-400 dark:hover:text-primary-300', FOCUS_RING),
|
|
58
121
|
onClick: function onClick(e) {
|
|
59
122
|
if (item.onClick) {
|
|
60
123
|
e.preventDefault();
|
|
61
124
|
item.onClick(item);
|
|
62
125
|
}
|
|
63
126
|
},
|
|
64
|
-
children:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}), item.label]
|
|
127
|
+
children: jsx(ItemContent, {
|
|
128
|
+
item: item
|
|
129
|
+
})
|
|
68
130
|
})]
|
|
69
131
|
}, itemKey(item, index));
|
|
70
132
|
})
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { objectWithoutProperties as _objectWithoutProperties,
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { PRESS_FEEDBACK } from '../../utils/touchTarget.js';
|
|
6
7
|
|
|
7
|
-
var _excluded = ["items", "className"]
|
|
8
|
+
var _excluded = ["items", "linkAs", "hideOnScroll", "badgeMax", "className", "onFocus"],
|
|
9
|
+
_excluded2 = ["className"];
|
|
8
10
|
var hasBadge = function hasBadge(badge) {
|
|
9
11
|
return badge === 0 || Boolean(badge);
|
|
10
12
|
};
|
|
@@ -17,34 +19,100 @@ var passthrough = function passthrough(item) {
|
|
|
17
19
|
return /^(aria|data)-/.test(key);
|
|
18
20
|
}));
|
|
19
21
|
};
|
|
22
|
+
// Numeric counts above `max` read `${max}+` so a big number can't widen the tab.
|
|
23
|
+
var formatBadge = function formatBadge(badge, max) {
|
|
24
|
+
return typeof badge === 'number' && typeof max === 'number' && badge > max ? "".concat(max, "+") : badge;
|
|
25
|
+
};
|
|
20
26
|
var Badge = function Badge(_ref3) {
|
|
21
|
-
var badge = _ref3.badge
|
|
27
|
+
var badge = _ref3.badge,
|
|
28
|
+
max = _ref3.max;
|
|
22
29
|
return jsx("span", {
|
|
23
|
-
className: "absolute -top-1.5 left-full -ml-2 flex h-4 min-w-4 items-center justify-center rounded-full bg-error-600 px-1 text-micro font-semibold text-white",
|
|
30
|
+
className: "absolute -top-1.5 left-full -ml-2 flex h-4 min-w-4 items-center justify-center whitespace-nowrap rounded-full bg-error-600 px-1 text-micro font-semibold tabular-nums text-white",
|
|
24
31
|
"data-slot": "badge",
|
|
25
|
-
children: badge
|
|
32
|
+
children: formatBadge(badge, max)
|
|
26
33
|
});
|
|
27
34
|
};
|
|
35
|
+
// Scroll distance (px) that counts as a direction change, and the offset
|
|
36
|
+
// before the bar may hide (so it never hides at the very top of the page).
|
|
37
|
+
var SCROLL_DELTA = 8;
|
|
38
|
+
var HIDE_AFTER = 64;
|
|
39
|
+
// Hide on scroll down, show on scroll up. Passive listener; SSR-safe (the
|
|
40
|
+
// effect only runs in the browser).
|
|
41
|
+
function useHideOnScroll(enabled) {
|
|
42
|
+
var _React$useState = React.useState(false),
|
|
43
|
+
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
44
|
+
hidden = _React$useState2[0],
|
|
45
|
+
setHidden = _React$useState2[1];
|
|
46
|
+
React.useEffect(function () {
|
|
47
|
+
if (!enabled || typeof window === 'undefined') {
|
|
48
|
+
setHidden(false);
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
var lastY = window.scrollY || 0;
|
|
52
|
+
var onScroll = function onScroll() {
|
|
53
|
+
var y = window.scrollY || 0;
|
|
54
|
+
var delta = y - lastY;
|
|
55
|
+
if (Math.abs(delta) < SCROLL_DELTA) return;
|
|
56
|
+
setHidden(delta > 0 && y > HIDE_AFTER);
|
|
57
|
+
lastY = y;
|
|
58
|
+
};
|
|
59
|
+
window.addEventListener('scroll', onScroll, {
|
|
60
|
+
passive: true
|
|
61
|
+
});
|
|
62
|
+
return function () {
|
|
63
|
+
return window.removeEventListener('scroll', onScroll);
|
|
64
|
+
};
|
|
65
|
+
}, [enabled]);
|
|
66
|
+
return [hidden, setHidden];
|
|
67
|
+
}
|
|
28
68
|
var FootNav = /*#__PURE__*/React.forwardRef(function (_ref4, ref) {
|
|
29
69
|
var _ref4$items = _ref4.items,
|
|
30
70
|
items = _ref4$items === void 0 ? [] : _ref4$items,
|
|
71
|
+
linkAs = _ref4.linkAs,
|
|
72
|
+
_ref4$hideOnScroll = _ref4.hideOnScroll,
|
|
73
|
+
hideOnScroll = _ref4$hideOnScroll === void 0 ? false : _ref4$hideOnScroll,
|
|
74
|
+
_ref4$badgeMax = _ref4.badgeMax,
|
|
75
|
+
badgeMax = _ref4$badgeMax === void 0 ? 99 : _ref4$badgeMax,
|
|
31
76
|
className = _ref4.className,
|
|
77
|
+
onFocus = _ref4.onFocus,
|
|
32
78
|
props = _objectWithoutProperties(_ref4, _excluded);
|
|
79
|
+
var _useHideOnScroll = useHideOnScroll(hideOnScroll),
|
|
80
|
+
_useHideOnScroll2 = _slicedToArray(_useHideOnScroll, 2),
|
|
81
|
+
hidden = _useHideOnScroll2[0],
|
|
82
|
+
setHidden = _useHideOnScroll2[1];
|
|
83
|
+
// Keyboard focus moving into a hidden bar brings it back.
|
|
84
|
+
var handleFocus = function handleFocus(e) {
|
|
85
|
+
if (hidden) setHidden(false);
|
|
86
|
+
onFocus === null || onFocus === void 0 || onFocus(e);
|
|
87
|
+
};
|
|
33
88
|
return jsx("nav", _objectSpread2(_objectSpread2({
|
|
34
89
|
ref: ref,
|
|
35
|
-
|
|
90
|
+
"aria-label": "Primary",
|
|
91
|
+
"data-hidden": hideOnScroll ? String(hidden) : undefined,
|
|
92
|
+
className: cn('fixed bottom-0 left-0 right-0 z-sticky border-t border-line px-2 pb-safe md:hidden',
|
|
93
|
+
// Translucent where backdrop blur is supported, solid surface otherwise.
|
|
94
|
+
'bg-surface supports-[backdrop-filter]:bg-surface/80 supports-[backdrop-filter]:backdrop-blur', hideOnScroll && 'transition-transform duration-base ease-standard motion-reduce:transition-none', hideOnScroll && hidden && 'translate-y-full', className),
|
|
95
|
+
onFocus: handleFocus
|
|
36
96
|
}, props), {}, {
|
|
37
97
|
children: jsx("div", {
|
|
38
|
-
className: "flex items-stretch justify-around gap-1",
|
|
98
|
+
className: "flex items-stretch justify-around gap-1 py-2",
|
|
39
99
|
children: items.map(function (item, index) {
|
|
40
|
-
var _item$id;
|
|
100
|
+
var _item$to, _item$id;
|
|
41
101
|
var isAction = item.variant === 'action';
|
|
42
|
-
|
|
43
|
-
|
|
102
|
+
var isLink = item.href !== undefined || item.to !== undefined;
|
|
103
|
+
var Item = isLink ? linkAs || 'a' : 'button';
|
|
104
|
+
var linkProps = isLink ? _objectSpread2({
|
|
105
|
+
href: item.href
|
|
106
|
+
}, linkAs ? {
|
|
107
|
+
to: (_item$to = item.to) !== null && _item$to !== void 0 ? _item$to : item.href
|
|
108
|
+
} : {}) : {
|
|
109
|
+
type: 'button'
|
|
110
|
+
};
|
|
111
|
+
return jsxs(Item, _objectSpread2(_objectSpread2(_objectSpread2({}, linkProps), {}, {
|
|
44
112
|
"aria-current": item.active ? 'page' : undefined,
|
|
45
113
|
"data-variant": isAction ? 'action' : undefined
|
|
46
114
|
}, passthrough(item)), {}, {
|
|
47
|
-
className: cn('relative flex min-w-0 flex-1 flex-col items-center gap-1 rounded-md px-1 py-2 text-xs transition-
|
|
115
|
+
className: cn('relative flex min-w-0 flex-1 flex-col items-center gap-1 rounded-md px-1 py-2 text-xs no-underline', PRESS_FEEDBACK, 'transition duration-fast ease-standard motion-reduce:transition-none', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-gray-900', isAction ? 'group justify-start py-0 font-medium text-muted' : item.active ? 'bg-primary-50 font-semibold text-primary-700 dark:bg-primary-900/40 dark:text-primary-300' : 'font-medium text-muted hover:bg-gray-100 hover:text-foreground dark:hover:bg-gray-800'),
|
|
48
116
|
onClick: function onClick() {
|
|
49
117
|
var _item$onClick;
|
|
50
118
|
return (_item$onClick = item.onClick) === null || _item$onClick === void 0 ? void 0 : _item$onClick.call(item, item);
|
|
@@ -56,13 +124,15 @@ var FootNav = /*#__PURE__*/React.forwardRef(function (_ref4, ref) {
|
|
|
56
124
|
className: "relative -mt-7 inline-flex h-14 w-14 items-center justify-center rounded-full bg-primary-600 text-2xl text-white shadow-lg ring-4 ring-surface transition-colors group-hover:bg-primary-700 motion-reduce:transition-none",
|
|
57
125
|
"data-slot": "icon",
|
|
58
126
|
children: [item.icon, hasBadge(item.badge) && jsx(Badge, {
|
|
59
|
-
badge: item.badge
|
|
127
|
+
badge: item.badge,
|
|
128
|
+
max: badgeMax
|
|
60
129
|
})]
|
|
61
130
|
}) : jsxs("span", {
|
|
62
131
|
className: "relative inline-flex text-lg",
|
|
63
132
|
"data-slot": "icon",
|
|
64
133
|
children: [item.icon, hasBadge(item.badge) && jsx(Badge, {
|
|
65
|
-
badge: item.badge
|
|
134
|
+
badge: item.badge,
|
|
135
|
+
max: badgeMax
|
|
66
136
|
})]
|
|
67
137
|
}), jsx("span", {
|
|
68
138
|
className: "block max-w-full truncate",
|
|
@@ -74,5 +144,24 @@ var FootNav = /*#__PURE__*/React.forwardRef(function (_ref4, ref) {
|
|
|
74
144
|
}));
|
|
75
145
|
});
|
|
76
146
|
FootNav.displayName = 'FootNav';
|
|
147
|
+
// Reserves the bar's height plus the bottom safe area at the end of the page
|
|
148
|
+
// content, so nothing scrolls under the fixed bar. Hidden from `md` up, like
|
|
149
|
+
// the bar itself.
|
|
150
|
+
var FootNavSpacer = /*#__PURE__*/React.forwardRef(function (_ref5, ref) {
|
|
151
|
+
var className = _ref5.className,
|
|
152
|
+
props = _objectWithoutProperties(_ref5, _excluded2);
|
|
153
|
+
return jsx("div", _objectSpread2(_objectSpread2({
|
|
154
|
+
ref: ref,
|
|
155
|
+
"aria-hidden": "true",
|
|
156
|
+
"data-slot": "footnav-spacer",
|
|
157
|
+
className: cn('pb-safe md:hidden', className)
|
|
158
|
+
}, props), {}, {
|
|
159
|
+
children: jsx("div", {
|
|
160
|
+
className: "h-20"
|
|
161
|
+
})
|
|
162
|
+
}));
|
|
163
|
+
});
|
|
164
|
+
FootNavSpacer.displayName = 'FootNav.Spacer';
|
|
165
|
+
FootNav.Spacer = FootNavSpacer;
|
|
77
166
|
|
|
78
167
|
export { FootNav as default };
|
|
@@ -6,6 +6,8 @@ import { cn } from '../../utils/cn.js';
|
|
|
6
6
|
import { ChevronRight, ChevronLeft, ChevronDown } from 'lucide-react';
|
|
7
7
|
import Tooltip from '../core/Tooltip.js';
|
|
8
8
|
import { useLatestRef } from '../../hooks/useLatestRef.js';
|
|
9
|
+
import { useFocusTrap } from '../../hooks/useFocusTrap.js';
|
|
10
|
+
import { useScrollLock } from '../../hooks/useScrollLock.js';
|
|
9
11
|
|
|
10
12
|
var _excluded = ["items", "collapsed", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange"];
|
|
11
13
|
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
@@ -15,13 +17,6 @@ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect
|
|
|
15
17
|
var isModifiedClick = function isModifiedClick(e) {
|
|
16
18
|
return Boolean(e && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || typeof e.button === "number" && e.button !== 0));
|
|
17
19
|
};
|
|
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
20
|
var hasChildItems = function hasChildItems(item) {
|
|
26
21
|
return Array.isArray(item.children) && item.children.length > 0;
|
|
27
22
|
};
|
|
@@ -171,12 +166,8 @@ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
171
166
|
var setIsMobileOpenRef = useLatestRef(setIsMobileOpen);
|
|
172
167
|
var mobileOpen = isMobileOpen !== null && isMobileOpen !== void 0 ? isMobileOpen : false;
|
|
173
168
|
var effectiveCollapsed = mobileOpen ? false : collapsed;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return function () {
|
|
177
|
-
document.body.style.overflow = "";
|
|
178
|
-
};
|
|
179
|
-
}, [mobileOpen]);
|
|
169
|
+
// Ref-counted, so a Dialog/Drawer stacked on top never unlocks the page early.
|
|
170
|
+
useScrollLock(mobileOpen);
|
|
180
171
|
// The drawer stays mounted (it slides in/out), so when it is shut it must
|
|
181
172
|
// leave the tab order and the a11y tree. `inert` is set imperatively: React
|
|
182
173
|
// 18 does not know the attribute and React 19 treats `inert=""` as false.
|
|
@@ -185,54 +176,15 @@ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
185
176
|
if (!drawer) return;
|
|
186
177
|
if (mobileOpen) drawer.removeAttribute("inert");else drawer.setAttribute("inert", "");
|
|
187
178
|
}, [mobileOpen]);
|
|
188
|
-
// Open drawer = modal dialog: initial focus inside, Tab trapped
|
|
189
|
-
// closes, focus returns to the opener
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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]);
|
|
179
|
+
// Open drawer = modal dialog: initial focus inside, Tab trapped (skipped
|
|
180
|
+
// while md:hidden hides it), Escape closes, focus returns to the opener.
|
|
181
|
+
useFocusTrap(drawerRef, {
|
|
182
|
+
active: mobileOpen,
|
|
183
|
+
onEscape: function onEscape() {
|
|
184
|
+
var _setIsMobileOpenRef$c;
|
|
185
|
+
return (_setIsMobileOpenRef$c = setIsMobileOpenRef.current) === null || _setIsMobileOpenRef$c === void 0 ? void 0 : _setIsMobileOpenRef$c.call(setIsMobileOpenRef, false);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
236
188
|
var closeMobile = function closeMobile() {
|
|
237
189
|
if (mobileOpen && setIsMobileOpen) setIsMobileOpen(false);
|
|
238
190
|
};
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { cn } from '../../utils/cn.js';
|
|
6
6
|
import { User } from 'lucide-react';
|
|
7
7
|
|
|
8
8
|
var _excluded = ["src", "alt", "name", "size", "shape", "status", "className"];
|
|
9
|
+
// Internal (not exported from the package): shared with AvatarGroup's "+N" tile.
|
|
10
|
+
var AVATAR_SIZES = {
|
|
11
|
+
xs: 'h-6 w-6 text-xs',
|
|
12
|
+
sm: 'h-8 w-8 text-sm',
|
|
13
|
+
md: 'h-10 w-10 text-base',
|
|
14
|
+
lg: 'h-12 w-12 text-lg',
|
|
15
|
+
xl: 'h-16 w-16 text-xl',
|
|
16
|
+
'2xl': 'h-20 w-20 text-2xl'
|
|
17
|
+
};
|
|
9
18
|
var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
10
19
|
var src = _ref.src,
|
|
11
20
|
alt = _ref.alt,
|
|
@@ -17,14 +26,23 @@ var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
17
26
|
status = _ref.status,
|
|
18
27
|
className = _ref.className,
|
|
19
28
|
props = _objectWithoutProperties(_ref, _excluded);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// State-driven fallback: a broken image swaps to initials / icon without
|
|
30
|
+
// touching the DOM directly. Reset whenever `src` changes
|
|
31
|
+
// (adjust-during-render pattern).
|
|
32
|
+
var _React$useState = React.useState(false),
|
|
33
|
+
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
34
|
+
imgFailed = _React$useState2[0],
|
|
35
|
+
setImgFailed = _React$useState2[1];
|
|
36
|
+
var _React$useState3 = React.useState(src),
|
|
37
|
+
_React$useState4 = _slicedToArray(_React$useState3, 2),
|
|
38
|
+
prevSrc = _React$useState4[0],
|
|
39
|
+
setPrevSrc = _React$useState4[1];
|
|
40
|
+
if (src !== prevSrc) {
|
|
41
|
+
setPrevSrc(src);
|
|
42
|
+
setImgFailed(false);
|
|
43
|
+
}
|
|
44
|
+
var showImage = Boolean(src) && !imgFailed;
|
|
45
|
+
var sizes = AVATAR_SIZES;
|
|
28
46
|
var getInitials = function getInitials(name) {
|
|
29
47
|
if (!name) return '';
|
|
30
48
|
return name.split(' ').map(function (word) {
|
|
@@ -33,7 +51,7 @@ var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
33
51
|
};
|
|
34
52
|
var statusColors = {
|
|
35
53
|
online: 'bg-success-500',
|
|
36
|
-
offline: 'bg-gray-400',
|
|
54
|
+
offline: 'bg-gray-400 dark:bg-gray-500',
|
|
37
55
|
away: 'bg-warning-500',
|
|
38
56
|
busy: 'bg-error-500'
|
|
39
57
|
};
|
|
@@ -48,14 +66,14 @@ var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
48
66
|
return jsxs("div", {
|
|
49
67
|
ref: ref,
|
|
50
68
|
className: "relative inline-block",
|
|
51
|
-
children: [
|
|
52
|
-
className: cn('flex items-center justify-center bg-gray-100 text-primary-600 font-medium', sizes[size], {
|
|
69
|
+
children: [jsx("div", _objectSpread2(_objectSpread2({
|
|
70
|
+
className: cn('flex items-center justify-center bg-gray-100 text-primary-600 font-medium dark:bg-gray-800 dark:text-primary-300', sizes[size], {
|
|
53
71
|
'rounded-full': shape === 'circle',
|
|
54
72
|
'rounded-md': shape === 'square',
|
|
55
73
|
'rounded-lg': shape === 'rounded'
|
|
56
74
|
}, className)
|
|
57
75
|
}, props), {}, {
|
|
58
|
-
children:
|
|
76
|
+
children: showImage ? jsx("img", {
|
|
59
77
|
src: src,
|
|
60
78
|
alt: alt || name,
|
|
61
79
|
className: cn('h-full w-full object-cover', {
|
|
@@ -63,27 +81,24 @@ var Avatar = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
63
81
|
'rounded-md': shape === 'square',
|
|
64
82
|
'rounded-lg': shape === 'rounded'
|
|
65
83
|
}),
|
|
66
|
-
onError: function onError(
|
|
67
|
-
|
|
68
|
-
e.target.nextSibling.style.display = 'flex';
|
|
84
|
+
onError: function onError() {
|
|
85
|
+
return setImgFailed(true);
|
|
69
86
|
}
|
|
70
|
-
}) :
|
|
87
|
+
}) : jsx("div", {
|
|
71
88
|
className: cn('flex items-center justify-center h-full w-full', {
|
|
72
89
|
'rounded-full': shape === 'circle',
|
|
73
90
|
'rounded-md': shape === 'square',
|
|
74
91
|
'rounded-lg': shape === 'rounded'
|
|
75
|
-
}, {
|
|
76
|
-
'hidden': src
|
|
77
92
|
}),
|
|
78
93
|
children: name ? getInitials(name) : jsx(User, {
|
|
79
94
|
className: "h-1/2 w-1/2"
|
|
80
95
|
})
|
|
81
|
-
})
|
|
96
|
+
})
|
|
82
97
|
})), status && jsx("span", {
|
|
83
|
-
className: cn('absolute bottom-0 right-0 rounded-full border-2 border-
|
|
98
|
+
className: cn('absolute bottom-0 right-0 rounded-full border-2 border-surface', statusColors[status], statusSizes[size])
|
|
84
99
|
})]
|
|
85
100
|
});
|
|
86
101
|
});
|
|
87
102
|
Avatar.displayName = 'Avatar';
|
|
88
103
|
|
|
89
|
-
export { Avatar as default };
|
|
104
|
+
export { AVATAR_SIZES, Avatar as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs } from 'react/jsx-runtime';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { cn } from '../../utils/cn.js';
|
|
6
|
+
import { AVATAR_SIZES } from './Avatar.js';
|
|
7
|
+
|
|
8
|
+
var _excluded = ["children", "max", "size", "className"];
|
|
9
|
+
// Overlap grows with the avatar so the stack reads the same at every size.
|
|
10
|
+
var OVERLAP = {
|
|
11
|
+
xs: '-space-x-1.5',
|
|
12
|
+
sm: '-space-x-2',
|
|
13
|
+
md: '-space-x-2',
|
|
14
|
+
lg: '-space-x-3',
|
|
15
|
+
xl: '-space-x-4',
|
|
16
|
+
'2xl': '-space-x-5'
|
|
17
|
+
};
|
|
18
|
+
// Each avatar is ringed in the surface colour so it reads as cut out of the
|
|
19
|
+
// one behind it (dark-mode aware).
|
|
20
|
+
var RING = 'ring-2 ring-surface';
|
|
21
|
+
var AvatarGroup = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
22
|
+
var children = _ref.children,
|
|
23
|
+
max = _ref.max,
|
|
24
|
+
_ref$size = _ref.size,
|
|
25
|
+
size = _ref$size === void 0 ? 'md' : _ref$size,
|
|
26
|
+
className = _ref.className,
|
|
27
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
28
|
+
var avatars = React.Children.toArray(children).filter(React.isValidElement);
|
|
29
|
+
var limit = typeof max === 'number' && max >= 0 ? max : avatars.length;
|
|
30
|
+
var visible = avatars.slice(0, limit);
|
|
31
|
+
var overflow = avatars.length - visible.length;
|
|
32
|
+
var sizeKey = AVATAR_SIZES[size] ? size : 'md';
|
|
33
|
+
return jsxs("div", _objectSpread2(_objectSpread2({
|
|
34
|
+
ref: ref,
|
|
35
|
+
role: "group",
|
|
36
|
+
className: cn('flex items-center', OVERLAP[sizeKey], className)
|
|
37
|
+
}, props), {}, {
|
|
38
|
+
children: [visible.map(function (child) {
|
|
39
|
+
var _child$props$size;
|
|
40
|
+
return /*#__PURE__*/React.cloneElement(child, {
|
|
41
|
+
// An avatar's own `size` wins; otherwise the group's size applies.
|
|
42
|
+
size: (_child$props$size = child.props.size) !== null && _child$props$size !== void 0 ? _child$props$size : size,
|
|
43
|
+
className: cn(RING, child.props.className)
|
|
44
|
+
});
|
|
45
|
+
}), overflow > 0 && jsxs("span", {
|
|
46
|
+
role: "img",
|
|
47
|
+
"aria-label": "".concat(overflow, " more"),
|
|
48
|
+
"data-slot": "overflow",
|
|
49
|
+
className: cn('relative inline-flex shrink-0 items-center justify-center rounded-full bg-gray-200 font-medium text-gray-700 dark:bg-gray-700 dark:text-gray-100', RING, AVATAR_SIZES[sizeKey]),
|
|
50
|
+
children: ["+", overflow]
|
|
51
|
+
})]
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
AvatarGroup.displayName = 'AvatarGroup';
|
|
55
|
+
|
|
56
|
+
export { AvatarGroup as default };
|