@dreamtree-org/twreact-ui 1.3.10 → 2.0.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/README.md +70 -6
- package/ai-skills/dreamtree-ui.md +58 -15
- package/codemods/v2.cjs +198 -0
- package/dist/ai-schema.json +745 -53
- package/dist/charts/index.js +195 -66
- package/dist/components/blocks/AppShell.d.ts.map +1 -1
- package/dist/components/blocks/BottomActionBar.d.ts +6 -0
- package/dist/components/blocks/BottomActionBar.d.ts.map +1 -0
- package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -1
- package/dist/components/blocks/PageHeader.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/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/Loader.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/Popover.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/SearchField.d.ts +9 -0
- package/dist/components/core/SearchField.d.ts.map +1 -0
- package/dist/components/core/SegmentedControl.d.ts +8 -0
- package/dist/components/core/SegmentedControl.d.ts.map +1 -0
- 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.map +1 -1
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/SwipeableListItem.d.ts +4 -0
- package/dist/components/core/SwipeableListItem.d.ts.map +1 -0
- package/dist/components/core/SwipeableListItemGesture.d.ts +58 -0
- package/dist/components/core/SwipeableListItemGesture.d.ts.map +1 -0
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts +10 -3
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +10 -1
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/MobileFilters.d.ts +8 -2
- package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +2 -1
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts +5 -8
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts.map +1 -1
- package/dist/components/core/ThreeDotPopover.d.ts +10 -22
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts +2 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/core/internal/Calendar.d.ts +77 -0
- package/dist/components/core/internal/Calendar.d.ts.map +1 -0
- package/dist/components/core/menu/ActionMenuSurface.d.ts +42 -0
- package/dist/components/core/menu/ActionMenuSurface.d.ts.map +1 -0
- package/dist/components/core/menu/ActionSheetMenu.d.ts +17 -0
- package/dist/components/core/menu/ActionSheetMenu.d.ts.map +1 -0
- package/dist/components/core/menu/MenuPopover.d.ts +21 -0
- package/dist/components/core/menu/MenuPopover.d.ts.map +1 -0
- package/dist/components/core/menu/menuItems.d.ts +21 -0
- package/dist/components/core/menu/menuItems.d.ts.map +1 -0
- package/dist/components/core/menu/menuKeyboard.d.ts +16 -0
- package/dist/components/core/menu/menuKeyboard.d.ts.map +1 -0
- package/dist/components/feedback/ActionSheet.d.ts +4 -0
- package/dist/components/feedback/ActionSheet.d.ts.map +1 -0
- package/dist/components/feedback/Alert.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts.map +1 -1
- package/dist/components/feedback/Sheet.d.ts +4 -0
- package/dist/components/feedback/Sheet.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +4 -3
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/ToastItem.d.ts +47 -0
- package/dist/components/feedback/ToastItem.d.ts.map +1 -0
- package/dist/components/feedback/ToastStack.d.ts +20 -0
- package/dist/components/feedback/ToastStack.d.ts.map +1 -0
- package/dist/components/feedback/ToastSwipe.d.ts +22 -0
- package/dist/components/feedback/ToastSwipe.d.ts.map +1 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -1
- package/dist/components/feedback/sheetCore.d.ts +30 -0
- package/dist/components/feedback/sheetCore.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 +6 -0
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -1
- package/dist/components/rich-text/RichTextToolbar.d.ts +6 -2
- package/dist/components/rich-text/RichTextToolbar.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/PullToRefresh.d.ts +5 -0
- package/dist/components/utility/PullToRefresh.d.ts.map +1 -0
- 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 +97 -90
- package/dist/esm/components/blocks/BottomActionBar.js +132 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +40 -4
- 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/PageHeader.js +16 -3
- 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/Button.js +49 -25
- package/dist/esm/components/core/Checkbox.js +72 -57
- package/dist/esm/components/core/ColorPicker.js +31 -42
- package/dist/esm/components/core/DatePicker.js +117 -304
- package/dist/esm/components/core/DateRangePicker.js +260 -308
- package/dist/esm/components/core/Form.js +11 -2
- package/dist/esm/components/core/Input.js +100 -38
- package/dist/esm/components/core/Loader.js +30 -44
- package/dist/esm/components/core/LocationPicker.js +82 -16
- package/dist/esm/components/core/Popover.js +59 -48
- package/dist/esm/components/core/ProgressBar.js +40 -72
- package/dist/esm/components/core/Radio.js +10 -12
- package/dist/esm/components/core/Rate.js +77 -14
- package/dist/esm/components/core/RoundedTag.js +5 -5
- package/dist/esm/components/core/SearchField.js +311 -0
- package/dist/esm/components/core/SegmentedControl.js +189 -0
- package/dist/esm/components/core/Select.js +185 -190
- 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/SwipeableListItem.js +286 -0
- package/dist/esm/components/core/SwipeableListItemGesture.js +219 -0
- package/dist/esm/components/core/Switch.js +98 -28
- package/dist/esm/components/core/Table/ActionMenu.js +45 -231
- package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
- package/dist/esm/components/core/Table/MobileCard.js +66 -16
- package/dist/esm/components/core/Table/MobileFilters.js +181 -10
- package/dist/esm/components/core/Table/Table.js +149 -102
- package/dist/esm/components/core/Table/TableRow.js +10 -2
- package/dist/esm/components/core/Tabs.js +186 -39
- package/dist/esm/components/core/Textarea.js +10 -2
- package/dist/esm/components/core/ThreeDotPopover.js +93 -99
- package/dist/esm/components/core/Tooltip.js +138 -145
- package/dist/esm/components/core/internal/Calendar.js +381 -0
- package/dist/esm/components/core/menu/ActionMenuSurface.js +110 -0
- package/dist/esm/components/core/menu/ActionSheetMenu.js +140 -0
- package/dist/esm/components/core/menu/MenuPopover.js +177 -0
- package/dist/esm/components/core/menu/menuItems.js +61 -0
- package/dist/esm/components/core/menu/menuKeyboard.js +54 -0
- package/dist/esm/components/feedback/ActionSheet.js +55 -0
- package/dist/esm/components/feedback/Alert.js +63 -53
- package/dist/esm/components/feedback/Dialog.js +141 -53
- package/dist/esm/components/feedback/Drawer.js +130 -132
- package/dist/esm/components/feedback/Sheet.js +125 -0
- package/dist/esm/components/feedback/Toast.js +21 -291
- package/dist/esm/components/feedback/ToastItem.js +348 -0
- package/dist/esm/components/feedback/ToastStack.js +130 -0
- package/dist/esm/components/feedback/ToastSwipe.js +52 -0
- package/dist/esm/components/feedback/Tour.js +107 -30
- package/dist/esm/components/feedback/sheetCore.js +494 -0
- package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
- package/dist/esm/components/navigation/Dropdown.js +1 -1
- package/dist/esm/components/navigation/FootNav.js +102 -13
- package/dist/esm/components/navigation/Navbar.js +172 -37
- package/dist/esm/components/navigation/Sidebar.js +263 -111
- package/dist/esm/components/rich-text/RichTextEditor.js +9 -3
- package/dist/esm/components/rich-text/RichTextToolbar.js +29 -9
- package/dist/esm/components/utility/Avatar.js +14 -12
- 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 +139 -29
- package/dist/esm/components/utility/FileUpload.js +106 -31
- package/dist/esm/components/utility/Pagination.js +31 -13
- package/dist/esm/components/utility/Portal.js +31 -0
- package/dist/esm/components/utility/PullToRefresh.js +229 -0
- package/dist/esm/components/utility/Sortable.js +6 -2
- package/dist/esm/components/utility/Stepper.js +110 -47
- package/dist/esm/hooks/useFloatingPosition.js +82 -0
- package/dist/esm/hooks/useHaptics.js +65 -0
- package/dist/esm/hooks/usePresence.js +58 -0
- package/dist/esm/hooks/usePresentation.js +21 -0
- package/dist/esm/hooks/useSheetDrag.js +220 -0
- package/dist/esm/hooks/useSliderValues.js +8 -2
- package/dist/esm/hooks/useSortable.js +107 -5
- package/dist/esm/index.js +14 -2
- package/dist/esm/utils/position.js +10 -63
- package/dist/esm/utils/touchTarget.js +4 -1
- package/dist/hooks/useFloatingPosition.d.ts +8 -4
- package/dist/hooks/useFloatingPosition.d.ts.map +1 -1
- package/dist/hooks/useHaptics.d.ts +19 -0
- package/dist/hooks/useHaptics.d.ts.map +1 -0
- package/dist/hooks/useSheetDrag.d.ts +31 -0
- package/dist/hooks/useSheetDrag.d.ts.map +1 -0
- 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 +11 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +10645 -3842
- package/dist/index.js +10657 -3845
- package/dist/rich-text/index.js +41 -11
- package/dist/types/blocks.d.ts +32 -2
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/charts.d.ts +3 -1
- package/dist/types/charts.d.ts.map +1 -1
- package/dist/types/index.d.ts +409 -26
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/rich-text.d.ts +5 -0
- package/dist/types/rich-text.d.ts.map +1 -1
- package/dist/utils/position.d.ts +0 -15
- package/dist/utils/position.d.ts.map +1 -1
- package/doc/README.md +16 -0
- package/mcp/catalog.snapshot.json +1540 -407
- package/package.json +7 -2
- package/dist/esm/hooks/useSwipeToClose.js +0 -66
- package/dist/hooks/useSwipeToClose.d.ts +0 -24
- package/dist/hooks/useSwipeToClose.d.ts.map +0 -1
|
@@ -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 };
|
|
@@ -2,15 +2,70 @@
|
|
|
2
2
|
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { cn } from '../../utils/cn.js';
|
|
5
|
-
import React, { useState, useCallback, useEffect } from 'react';
|
|
5
|
+
import React, { useState, useRef, useCallback, useEffect, useSyncExternalStore } from 'react';
|
|
6
6
|
import { ChevronLeft, Search, LogIn, LogOut, X, Menu, User, Bell } from 'lucide-react';
|
|
7
7
|
import { Dropdown } from './Dropdown.js';
|
|
8
8
|
import Avatar from '../utility/Avatar.js';
|
|
9
|
+
import Sheet from '../feedback/Sheet.js';
|
|
10
|
+
import SearchField from '../core/SearchField.js';
|
|
11
|
+
import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
9
12
|
import PropTypes from '../../_vendor/prop-types/index.js';
|
|
10
13
|
|
|
11
14
|
var _excluded = ["emitter", "content", "notifications"],
|
|
12
|
-
_excluded2 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen"];
|
|
15
|
+
_excluded2 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen", "sticky", "largeTitle"];
|
|
13
16
|
var NO_NOTIFICATIONS = [];
|
|
17
|
+
// Icon-only bar buttons: 36px on desktop, the 44px touch target on coarse pointers.
|
|
18
|
+
var ICON_BUTTON = cn("inline-flex items-center justify-center rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100 dark:hover:bg-gray-800", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET);
|
|
19
|
+
// Badge counts above this read "99+".
|
|
20
|
+
var BADGE_MAX = 99;
|
|
21
|
+
var formatBadgeCount = function formatBadgeCount(count) {
|
|
22
|
+
return count > BADGE_MAX ? "".concat(BADGE_MAX, "+") : String(count);
|
|
23
|
+
};
|
|
24
|
+
// Large title: collapses past COLLAPSE_AT and re-expands under EXPAND_AT. The
|
|
25
|
+
// gap (hysteresis) stops the bar flickering when collapsing it shortens the page.
|
|
26
|
+
var LARGE_TITLE_COLLAPSE_AT = 44;
|
|
27
|
+
var LARGE_TITLE_EXPAND_AT = 8;
|
|
28
|
+
// Per-instance scroll store for useSyncExternalStore: one passive window
|
|
29
|
+
// scroll listener; `false` (expanded) on the server and while hydrating.
|
|
30
|
+
function createScrollCollapseStore() {
|
|
31
|
+
var collapsed = false;
|
|
32
|
+
var read = function read() {
|
|
33
|
+
var y = window.scrollY || window.pageYOffset || 0;
|
|
34
|
+
if (!collapsed && y > LARGE_TITLE_COLLAPSE_AT) collapsed = true;else if (collapsed && y < LARGE_TITLE_EXPAND_AT) collapsed = false;
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
subscribe: function subscribe(onChange) {
|
|
38
|
+
if (typeof window === "undefined") return function () {};
|
|
39
|
+
var handle = function handle() {
|
|
40
|
+
var prev = collapsed;
|
|
41
|
+
read();
|
|
42
|
+
if (prev !== collapsed) onChange();
|
|
43
|
+
};
|
|
44
|
+
handle();
|
|
45
|
+
window.addEventListener("scroll", handle, {
|
|
46
|
+
passive: true
|
|
47
|
+
});
|
|
48
|
+
return function () {
|
|
49
|
+
return window.removeEventListener("scroll", handle);
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
getSnapshot: function getSnapshot() {
|
|
53
|
+
return collapsed;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
var NEVER_SUBSCRIBE = function NEVER_SUBSCRIBE() {
|
|
58
|
+
return function () {};
|
|
59
|
+
};
|
|
60
|
+
var ALWAYS_FALSE = function ALWAYS_FALSE() {
|
|
61
|
+
return false;
|
|
62
|
+
};
|
|
63
|
+
function useLargeTitleCollapsed(enabled) {
|
|
64
|
+
var _useState = useState(createScrollCollapseStore),
|
|
65
|
+
_useState2 = _slicedToArray(_useState, 1),
|
|
66
|
+
store = _useState2[0];
|
|
67
|
+
return useSyncExternalStore(enabled ? store.subscribe : NEVER_SUBSCRIBE, enabled ? store.getSnapshot : ALWAYS_FALSE, ALWAYS_FALSE);
|
|
68
|
+
}
|
|
14
69
|
// Simplified Notifications, uses notifications from props and a single effect for fetch/update
|
|
15
70
|
var NotificationsDropdown = function NotificationsDropdown(_ref) {
|
|
16
71
|
var emitter = _ref.emitter,
|
|
@@ -20,10 +75,10 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
|
|
|
20
75
|
onFetch = _ref$onFetch === void 0 ? function () {
|
|
21
76
|
return console.log("invoked onFetch notifications");
|
|
22
77
|
} : _ref$onFetch;
|
|
23
|
-
var
|
|
24
|
-
|
|
25
|
-
notifications =
|
|
26
|
-
setNotifications =
|
|
78
|
+
var _useState3 = useState(initialNotifications),
|
|
79
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
80
|
+
notifications = _useState4[0],
|
|
81
|
+
setNotifications = _useState4[1];
|
|
27
82
|
var onView = function onView() {
|
|
28
83
|
emitter.emit("notification:view", notifications);
|
|
29
84
|
};
|
|
@@ -46,10 +101,10 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
|
|
|
46
101
|
};
|
|
47
102
|
// Reset to the `notifications` prop when it changes (adjust-during-render
|
|
48
103
|
// pattern), then let onFetch refresh from the server.
|
|
49
|
-
var
|
|
50
|
-
|
|
51
|
-
prevInitial =
|
|
52
|
-
setPrevInitial =
|
|
104
|
+
var _useState5 = useState(initialNotifications),
|
|
105
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
106
|
+
prevInitial = _useState6[0],
|
|
107
|
+
setPrevInitial = _useState6[1];
|
|
53
108
|
if (initialNotifications !== prevInitial) {
|
|
54
109
|
setPrevInitial(initialNotifications);
|
|
55
110
|
setNotifications(initialNotifications);
|
|
@@ -67,13 +122,19 @@ var NotificationsDropdown = function NotificationsDropdown(_ref) {
|
|
|
67
122
|
// For simplicity, shows notifications in the dropdown, can be expanded
|
|
68
123
|
return jsx(Dropdown, {
|
|
69
124
|
trigger: jsxs("button", {
|
|
70
|
-
|
|
71
|
-
|
|
125
|
+
type: "button",
|
|
126
|
+
className: cn(ICON_BUTTON, "relative"),
|
|
127
|
+
"aria-label": unreadCount > 0 ? "Notifications, ".concat(formatBadgeCount(unreadCount), " unread") : "Notifications",
|
|
72
128
|
children: [jsx(Bell, {
|
|
73
|
-
className: "h-5 w-5"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
129
|
+
className: "h-5 w-5",
|
|
130
|
+
"aria-hidden": "true"
|
|
131
|
+
}), unreadCount > 0 &&
|
|
132
|
+
// Grows with the count (min-w + padding) and caps at "99+".
|
|
133
|
+
jsx("span", {
|
|
134
|
+
"aria-hidden": "true",
|
|
135
|
+
"data-navbar-badge": "",
|
|
136
|
+
className: "absolute -right-0.5 -top-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-pill bg-error-500 px-1 text-micro font-semibold leading-none text-white",
|
|
137
|
+
children: formatBadgeCount(unreadCount)
|
|
77
138
|
})]
|
|
78
139
|
}),
|
|
79
140
|
placement: "bottom-end",
|
|
@@ -159,7 +220,7 @@ var RightMenuContent = function RightMenuContent(_ref2) {
|
|
|
159
220
|
});
|
|
160
221
|
};
|
|
161
222
|
var styledClassNames = {
|
|
162
|
-
button:
|
|
223
|
+
button: ICON_BUTTON,
|
|
163
224
|
mobileItem: "md:hidden",
|
|
164
225
|
icon: "h-6 w-6",
|
|
165
226
|
dropdown: "w-56 rounded-md border border-line bg-surface py-1 shadow-lg"
|
|
@@ -192,19 +253,29 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
192
253
|
onFetch = _ref3.onFetch;
|
|
193
254
|
_ref3.isMobileOpen;
|
|
194
255
|
_ref3.setIsMobileOpen;
|
|
195
|
-
var
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
var _useState7 = useState(""),
|
|
256
|
+
var _ref3$sticky = _ref3.sticky,
|
|
257
|
+
sticky = _ref3$sticky === void 0 ? false : _ref3$sticky,
|
|
258
|
+
largeTitle = _ref3.largeTitle,
|
|
259
|
+
props = _objectWithoutProperties(_ref3, _excluded2);
|
|
260
|
+
var _useState7 = useState(false),
|
|
201
261
|
_useState8 = _slicedToArray(_useState7, 2),
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
var _useState9 = useState(
|
|
262
|
+
isMobileMenuOpen = _useState8[0],
|
|
263
|
+
setIsMobileMenuOpen = _useState8[1];
|
|
264
|
+
var _useState9 = useState(""),
|
|
205
265
|
_useState0 = _slicedToArray(_useState9, 2),
|
|
206
|
-
|
|
207
|
-
|
|
266
|
+
searchTerm = _useState0[0],
|
|
267
|
+
setSearchTerm = _useState0[1];
|
|
268
|
+
var _useState1 = useState(false),
|
|
269
|
+
_useState10 = _slicedToArray(_useState1, 2),
|
|
270
|
+
isMobileSearchOpen = _useState10[0],
|
|
271
|
+
setIsMobileSearchOpen = _useState10[1];
|
|
272
|
+
var mobileSearchRef = useRef(null);
|
|
273
|
+
var hasLargeTitle = largeTitle !== undefined && largeTitle !== null && largeTitle !== false;
|
|
274
|
+
var titleCollapsed = useLargeTitleCollapsed(hasLargeTitle);
|
|
275
|
+
var _useState11 = useState(typeof window !== "undefined" ? window.innerWidth < 768 : false),
|
|
276
|
+
_useState12 = _slicedToArray(_useState11, 2),
|
|
277
|
+
isMobile = _useState12[0],
|
|
278
|
+
setIsMobile = _useState12[1];
|
|
208
279
|
// Responsive flag update
|
|
209
280
|
var handleResize = useCallback(function () {
|
|
210
281
|
setIsMobile(window.innerWidth < 768);
|
|
@@ -221,6 +292,12 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
221
292
|
e.preventDefault();
|
|
222
293
|
onSearch === null || onSearch === void 0 || onSearch(searchTerm);
|
|
223
294
|
};
|
|
295
|
+
// Phones: the inline field is hidden below `sm`; a search button opens it
|
|
296
|
+
// in a top Sheet instead, sharing the same term and `onSearch`.
|
|
297
|
+
var handleMobileSearch = function handleMobileSearch(term) {
|
|
298
|
+
onSearch === null || onSearch === void 0 || onSearch(term);
|
|
299
|
+
setIsMobileSearchOpen(false);
|
|
300
|
+
};
|
|
224
301
|
var handleLoginClick = function handleLoginClick() {
|
|
225
302
|
onLoginClick === null || onLoginClick === void 0 || onLoginClick();
|
|
226
303
|
};
|
|
@@ -262,11 +339,17 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
262
339
|
};
|
|
263
340
|
return jsxs("nav", _objectSpread2(_objectSpread2({
|
|
264
341
|
ref: ref,
|
|
265
|
-
className: cn("bg-surface text-foreground border-b border-line px-4 sm:px-6 lg:px-8", className)
|
|
342
|
+
className: cn("bg-surface text-foreground border-b border-line px-4 sm:px-6 lg:px-8", sticky && "sticky top-0 z-sticky pt-safe supports-[backdrop-filter]:bg-surface/80 supports-[backdrop-filter]:backdrop-blur", className),
|
|
343
|
+
"data-sticky": sticky ? "" : undefined
|
|
266
344
|
}, props), {}, {
|
|
267
345
|
children: [jsxs("div", {
|
|
268
|
-
className: "flex h-16 min-w-0 items-center justify-between gap-2 sm:gap-4",
|
|
269
|
-
children: [
|
|
346
|
+
className: "relative flex h-16 min-w-0 items-center justify-between gap-2 sm:gap-4",
|
|
347
|
+
children: [hasLargeTitle && jsx("div", {
|
|
348
|
+
"aria-hidden": "true",
|
|
349
|
+
"data-navbar-compact-title": "",
|
|
350
|
+
className: cn("pointer-events-none absolute left-1/2 top-1/2 max-w-[50%] -translate-x-1/2 -translate-y-1/2 truncate text-base font-semibold", "transition-opacity duration-base ease-standard motion-reduce:transition-none", titleCollapsed ? "opacity-100" : "opacity-0"),
|
|
351
|
+
children: largeTitle
|
|
352
|
+
}), jsxs("div", {
|
|
270
353
|
className: "flex min-w-0 shrink items-center",
|
|
271
354
|
children: [leftIcon !== false && jsx("div", {
|
|
272
355
|
className: "mr-2 hidden md:block md:mr-4",
|
|
@@ -275,8 +358,9 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
275
358
|
className: "flex min-w-0 items-center",
|
|
276
359
|
children: [leftIcon !== false && jsx("button", {
|
|
277
360
|
onClick: onLeftIconClick,
|
|
278
|
-
|
|
279
|
-
"
|
|
361
|
+
type: "button",
|
|
362
|
+
className: cn(ICON_BUTTON, "shrink-0 md:hidden"),
|
|
363
|
+
"aria-label": "Go back",
|
|
280
364
|
children: leftIcon
|
|
281
365
|
}), logo && jsx("div", {
|
|
282
366
|
className: "ml-2 min-w-0 truncate sm:ml-4 md:ml-0",
|
|
@@ -309,6 +393,20 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
309
393
|
}
|
|
310
394
|
})]
|
|
311
395
|
})
|
|
396
|
+
}), searchable && jsx("button", {
|
|
397
|
+
type: "button",
|
|
398
|
+
className: cn(styledClassNames.button, "sm:hidden"),
|
|
399
|
+
onClick: function onClick() {
|
|
400
|
+
return setIsMobileSearchOpen(true);
|
|
401
|
+
},
|
|
402
|
+
"aria-label": "Search",
|
|
403
|
+
"aria-haspopup": "dialog",
|
|
404
|
+
"aria-expanded": isMobileSearchOpen,
|
|
405
|
+
"data-navbar-search-button": "",
|
|
406
|
+
children: jsx(Search, {
|
|
407
|
+
className: "h-5 w-5",
|
|
408
|
+
"aria-hidden": "true"
|
|
409
|
+
})
|
|
312
410
|
}), jsx(RightMenuComponent, {
|
|
313
411
|
notifications: notifications,
|
|
314
412
|
onFetch: onFetch
|
|
@@ -333,12 +431,14 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
333
431
|
className: "relative",
|
|
334
432
|
children: !user ? jsx("button", {
|
|
335
433
|
className: cn(styledClassNames.button, styledClassNames.mobileItem),
|
|
434
|
+
type: "button",
|
|
336
435
|
onClick: function onClick() {
|
|
337
436
|
return setIsMobileMenuOpen(function (s) {
|
|
338
437
|
return !s;
|
|
339
438
|
});
|
|
340
439
|
},
|
|
341
|
-
"aria-label": "menu",
|
|
440
|
+
"aria-label": isMobileMenuOpen ? "Close menu" : "Open menu",
|
|
441
|
+
"aria-expanded": isMobileMenuOpen,
|
|
342
442
|
children: isMobileMenuOpen ? jsx(X, {
|
|
343
443
|
className: styledClassNames.icon
|
|
344
444
|
}) : jsx(Menu, {
|
|
@@ -346,8 +446,9 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
346
446
|
})
|
|
347
447
|
}) : jsx(Dropdown, {
|
|
348
448
|
trigger: jsx("button", {
|
|
449
|
+
type: "button",
|
|
349
450
|
className: styledClassNames.button,
|
|
350
|
-
"aria-label": "
|
|
451
|
+
"aria-label": "User menu",
|
|
351
452
|
children: user.avatar || user.name ?
|
|
352
453
|
// Image when `avatar` is set; otherwise initials from
|
|
353
454
|
// `name` (Avatar's own fallback logic).
|
|
@@ -361,7 +462,7 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
361
462
|
})
|
|
362
463
|
}),
|
|
363
464
|
placement: "bottom-end",
|
|
364
|
-
className: "z-
|
|
465
|
+
className: "z-dropdown",
|
|
365
466
|
children: jsxs("div", {
|
|
366
467
|
className: styledClassNames.dropdown,
|
|
367
468
|
children: [jsxs("div", {
|
|
@@ -404,6 +505,38 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
404
505
|
})
|
|
405
506
|
})]
|
|
406
507
|
})]
|
|
508
|
+
}), hasLargeTitle && jsx("div", {
|
|
509
|
+
"data-navbar-large-title": "",
|
|
510
|
+
"data-collapsed": titleCollapsed ? "" : undefined,
|
|
511
|
+
className: cn("overflow-hidden transition-[max-height,opacity] duration-base ease-standard motion-reduce:transition-none", titleCollapsed ? "max-h-0 opacity-0" : "max-h-16 opacity-100"),
|
|
512
|
+
children: jsx("h1", {
|
|
513
|
+
className: "truncate pb-3 text-3xl font-bold tracking-tight text-foreground",
|
|
514
|
+
children: largeTitle
|
|
515
|
+
})
|
|
516
|
+
}), searchable && jsx(Sheet, {
|
|
517
|
+
open: isMobileSearchOpen,
|
|
518
|
+
onClose: function onClose() {
|
|
519
|
+
return setIsMobileSearchOpen(false);
|
|
520
|
+
},
|
|
521
|
+
placement: "top",
|
|
522
|
+
initialFocus: mobileSearchRef,
|
|
523
|
+
"aria-label": "Search",
|
|
524
|
+
"data-navbar-search-sheet": "",
|
|
525
|
+
children: jsx("div", {
|
|
526
|
+
className: "px-4 py-3",
|
|
527
|
+
children: jsx(SearchField, {
|
|
528
|
+
ref: mobileSearchRef,
|
|
529
|
+
presentation: "popover",
|
|
530
|
+
showCancel: true,
|
|
531
|
+
placeholder: "Search...",
|
|
532
|
+
value: searchTerm,
|
|
533
|
+
onValueChange: setSearchTerm,
|
|
534
|
+
onSearch: handleMobileSearch,
|
|
535
|
+
onCancel: function onCancel() {
|
|
536
|
+
return setIsMobileSearchOpen(false);
|
|
537
|
+
}
|
|
538
|
+
})
|
|
539
|
+
})
|
|
407
540
|
}), isMobileMenuOpen && !user && jsx("div", {
|
|
408
541
|
className: "md:hidden h-full",
|
|
409
542
|
children: jsx("div", {
|
|
@@ -431,7 +564,9 @@ Navbar.propTypes = {
|
|
|
431
564
|
user: PropTypes.object,
|
|
432
565
|
notifications: PropTypes.array,
|
|
433
566
|
searchable: PropTypes.bool,
|
|
434
|
-
onSearch: PropTypes.func
|
|
567
|
+
onSearch: PropTypes.func,
|
|
568
|
+
sticky: PropTypes.bool,
|
|
569
|
+
largeTitle: PropTypes.node
|
|
435
570
|
};
|
|
436
571
|
|
|
437
572
|
export { Navbar, Navbar as default };
|