@flamingo-stack/openframe-frontend-core 0.0.839 → 0.0.841
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/dist/build/export-map.json +1 -1
- package/dist/build/route-styles.cjs +3 -1
- package/dist/build/style-sources.cjs +15 -2
- package/dist/build/style-sources.d.ts +3 -0
- package/dist/{chunk-37XKZ4JM.cjs → chunk-275AQ6LC.cjs} +6 -6
- package/dist/{chunk-5BM7X4GA.cjs → chunk-5GBLXY5F.cjs} +2 -2
- package/dist/{chunk-5L3UKDC6.cjs → chunk-6LDL3UZE.cjs} +9 -9
- package/dist/{chunk-SWMUW3RR.cjs → chunk-744JXTDP.cjs} +19 -19
- package/dist/{chunk-46LATWQR.cjs → chunk-7WKRMJI6.cjs} +5 -5
- package/dist/{chunk-XJ4AB24Y.cjs → chunk-AT6D7BAZ.cjs} +5 -5
- package/dist/{chunk-C4OQIYGW.cjs → chunk-CCRXBFNL.cjs} +8 -8
- package/dist/{chunk-LC65AC6M.cjs → chunk-COWMXUHN.cjs} +2 -0
- package/dist/{chunk-5E4YEHHO.cjs → chunk-DGY5KEPY.cjs} +55 -55
- package/dist/{chunk-N2TCVIPR.cjs → chunk-DYDQLS2R.cjs} +539 -539
- package/dist/{chunk-LWMWY3JO.cjs → chunk-E7M54JWW.cjs} +14 -14
- package/dist/{chunk-Z7A7IZWL.cjs → chunk-EV6BPF47.cjs} +236 -210
- package/dist/{chunk-7XRFAHJF.cjs → chunk-FHI4I3TQ.cjs} +9 -9
- package/dist/{chunk-ZABZIM2Y.cjs → chunk-FRL2ZN4O.cjs} +3 -3
- package/dist/{chunk-7Z536SPR.cjs → chunk-FW7RKWPY.cjs} +15 -1
- package/dist/{chunk-3MBKEF7Z.cjs → chunk-GMK4JGC2.cjs} +46 -46
- package/dist/{chunk-SZVPRP5E.cjs → chunk-GUKFMMDZ.cjs} +3 -3
- package/dist/{chunk-GN6LEJWY.cjs → chunk-HXTZZE3R.cjs} +253 -131
- package/dist/{chunk-2XZZHRRU.cjs → chunk-IELPVUPR.cjs} +18 -18
- package/dist/{chunk-64PF3UC7.cjs → chunk-INBFKUZA.cjs} +17 -17
- package/dist/{chunk-APOMNC7H.cjs → chunk-IUDBG3HJ.cjs} +3 -3
- package/dist/{chunk-4JHO2NVI.cjs → chunk-J2IXYCEH.cjs} +26 -10
- package/dist/{chunk-C4RYIDPU.cjs → chunk-JM2XA7VY.cjs} +28 -28
- package/dist/{chunk-GPXKG34G.cjs → chunk-JUEAZCD6.cjs} +46 -46
- package/dist/{chunk-2QAUQPGC.cjs → chunk-MYAPG3FQ.cjs} +21 -21
- package/dist/{chunk-GRHF5SWL.cjs → chunk-NFNSPLGC.cjs} +3 -3
- package/dist/{chunk-UDRVVCOC.cjs → chunk-Q6WUHYOG.cjs} +72 -72
- package/dist/{chunk-H3WTYAVR.cjs → chunk-RSJYTQEA.cjs} +30 -30
- package/dist/{chunk-MG3HJIGG.cjs → chunk-UAI4VMEF.cjs} +4 -4
- package/dist/{chunk-S5RMRQKT.cjs → chunk-UZPYYHF5.cjs} +18 -18
- package/dist/{chunk-DFTXZE7B.cjs → chunk-VBH2RCFM.cjs} +73 -73
- package/dist/{chunk-FNNDGOR3.cjs → chunk-WCK5T3UD.cjs} +43 -43
- package/dist/{chunk-TRZEFT2N.cjs → chunk-WI7EXAZT.cjs} +9 -5
- package/dist/{chunk-TKS25VKE.cjs → chunk-Z35PL3UR.cjs} +32 -32
- package/dist/{chunk-ENK75WN4.cjs → chunk-ZAO5SYBJ.cjs} +4 -4
- package/dist/{cloud-tenants-WE3H3VAW.cjs → cloud-tenants-PV63RZ73.cjs} +19 -19
- package/dist/components/case-studies/index.cjs +33 -33
- package/dist/components/chat/chat-nav-sidebar.d.ts.map +1 -1
- package/dist/components/chat/chat-nav-sidebar.js +17 -3
- package/dist/components/chat/index.cjs +13 -13
- package/dist/components/contact/index.cjs +20 -20
- package/dist/components/docs/index.cjs +23 -23
- package/dist/components/embeds/index.cjs +20 -20
- package/dist/components/faq/index.cjs +21 -21
- package/dist/components/features/index.cjs +19 -19
- package/dist/components/help-center-pages/index.cjs +120 -120
- package/dist/components/index.cjs +76 -76
- package/dist/components/meeting-scheduler/index.cjs +82 -82
- package/dist/components/navigation/account-popover.d.ts.map +1 -1
- package/dist/components/navigation/account-popover.js +26 -2
- package/dist/components/navigation/app-layout-side-panel.d.ts.map +1 -1
- package/dist/components/navigation/app-layout-side-panel.js +2 -9
- package/dist/components/navigation/index.cjs +22 -22
- package/dist/components/navigation/navigation-sidebar-grouped.d.ts.map +1 -1
- package/dist/components/navigation/navigation-sidebar-grouped.js +30 -6
- package/dist/components/navigation/navigation-sidebar-item.d.ts.map +1 -1
- package/dist/components/navigation/navigation-sidebar-item.js +14 -1
- package/dist/components/navigation/navigation-sidebar.d.ts.map +1 -1
- package/dist/components/navigation/navigation-sidebar.js +72 -3
- package/dist/components/onboarding-guides/index.cjs +22 -22
- package/dist/components/product-demo/index.cjs +30 -30
- package/dist/components/related-content/index.cjs +8 -8
- package/dist/components/tickets/index.cjs +24 -24
- package/dist/components/ui/index.cjs +19 -19
- package/dist/components/ui/panel-resize-handle.d.ts +27 -6
- package/dist/components/ui/panel-resize-handle.d.ts.map +1 -1
- package/dist/components/ui/panel-resize-handle.js +27 -3
- package/dist/{devices-ZBZN2RRG.cjs → devices-VECG5JNC.cjs} +20 -20
- package/dist/{embeddable-chat-RBC7F4TL.cjs → embeddable-chat-VRYAQQF6.cjs} +90 -90
- package/dist/hooks/index.cjs +11 -7
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/index.js +1 -0
- package/dist/hooks/ui/use-clipped-label-tooltip.d.ts +14 -0
- package/dist/hooks/ui/use-clipped-label-tooltip.d.ts.map +1 -0
- package/dist/hooks/ui/use-clipped-label-tooltip.js +13 -0
- package/dist/hooks/ui/use-is-truncated.d.ts.map +1 -1
- package/dist/hooks/ui/use-is-truncated.js +1 -0
- package/dist/hooks/ui/use-media-query.d.ts.map +1 -1
- package/dist/hooks/ui/use-media-query.js +1 -0
- package/dist/hooks/ui/use-resizable-panel-size.d.ts +1 -0
- package/dist/hooks/ui/use-resizable-panel-size.d.ts.map +1 -1
- package/dist/hooks/ui/use-resizable-panel-size.js +5 -1
- package/dist/index.cjs +28 -24
- package/dist/{knowledge-2QNZGDFO.cjs → knowledge-YJSDJIXT.cjs} +20 -20
- package/dist/{logs-YPWTJVIH.cjs → logs-42JG3NZ5.cjs} +26 -26
- package/dist/{policies-BK7TUKAF.cjs → policies-D4QNVJ26.cjs} +23 -23
- package/dist/{remote-session-CN3G7JNR.cjs → remote-session-EE6477O3.cjs} +10 -10
- package/dist/{scripts-K7AOYWZE.cjs → scripts-4VFYBXBE.cjs} +26 -26
- package/dist/{software-update-UFN4SBMY.cjs → software-update-OSDZQ5CP.cjs} +23 -23
- package/dist/{tickets-board-PLYD2NSY.cjs → tickets-board-44HO3LR4.cjs} +10 -10
- package/dist/types/navigation.d.ts +36 -0
- package/dist/types/navigation.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-nav-sidebar.tsx +17 -4
- package/src/components/navigation/account-popover.tsx +31 -2
- package/src/components/navigation/app-layout-side-panel.tsx +2 -7
- package/src/components/navigation/navigation-sidebar-grouped.tsx +37 -6
- package/src/components/navigation/navigation-sidebar-item.tsx +18 -1
- package/src/components/navigation/navigation-sidebar.tsx +116 -7
- package/src/components/ui/panel-resize-handle.tsx +50 -8
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/use-clipped-label-tooltip.ts +20 -0
- package/src/hooks/ui/use-is-truncated.ts +2 -0
- package/src/hooks/ui/use-media-query.ts +2 -0
- package/src/hooks/ui/use-resizable-panel-size.ts +7 -1
- package/src/types/navigation.ts +37 -0
|
@@ -10,9 +10,9 @@ var _chunkFDZOE5TLcjs = require('./chunk-FDZOE5TL.cjs');
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
14
|
-
require('./chunk-
|
|
15
|
-
require('./chunk-
|
|
13
|
+
var _chunk744JXTDPcjs = require('./chunk-744JXTDP.cjs');
|
|
14
|
+
require('./chunk-IUDBG3HJ.cjs');
|
|
15
|
+
require('./chunk-6LDL3UZE.cjs');
|
|
16
16
|
require('./chunk-YJZ7R3W5.cjs');
|
|
17
17
|
require('./chunk-46547WQW.cjs');
|
|
18
18
|
require('./chunk-LNUFH4E2.cjs');
|
|
@@ -1806,7 +1806,7 @@ require('./chunk-XIBCMGBW.cjs');
|
|
|
1806
1806
|
require('./chunk-BUEEQD3G.cjs');
|
|
1807
1807
|
require('./chunk-WWUSFOJ7.cjs');
|
|
1808
1808
|
require('./chunk-SKI6NKOE.cjs');
|
|
1809
|
-
require('./chunk-
|
|
1809
|
+
require('./chunk-NFNSPLGC.cjs');
|
|
1810
1810
|
require('./chunk-JBTH3O2C.cjs');
|
|
1811
1811
|
require('./chunk-S5C3OZCO.cjs');
|
|
1812
1812
|
require('./chunk-32ASZMTV.cjs');
|
|
@@ -1815,7 +1815,7 @@ require('./chunk-4IYNDV3G.cjs');
|
|
|
1815
1815
|
require('./chunk-6VOOPMP5.cjs');
|
|
1816
1816
|
require('./chunk-ORO54HDF.cjs');
|
|
1817
1817
|
require('./chunk-RUHKTWGB.cjs');
|
|
1818
|
-
require('./chunk-
|
|
1818
|
+
require('./chunk-COWMXUHN.cjs');
|
|
1819
1819
|
require('./chunk-YSDB6HGQ.cjs');
|
|
1820
1820
|
require('./chunk-FX35L4Y6.cjs');
|
|
1821
1821
|
require('./chunk-JQCQCE6U.cjs');
|
|
@@ -1841,7 +1841,7 @@ function buildTicketsBoardFixture(cast) {
|
|
|
1841
1841
|
const dana = assignee(cast.person("dana"));
|
|
1842
1842
|
const alex = assignee(cast.person("alex"));
|
|
1843
1843
|
return [
|
|
1844
|
-
|
|
1844
|
+
_chunk744JXTDPcjs.columnFromTicketStatus.call(void 0, "ACTIVE", [
|
|
1845
1845
|
ticket("tk-1051", "Printer offline at the front desk", "ACTIVE", {
|
|
1846
1846
|
ticketNumber: "1051",
|
|
1847
1847
|
agent: "fae",
|
|
@@ -1859,7 +1859,7 @@ function buildTicketsBoardFixture(cast) {
|
|
|
1859
1859
|
tags: ["onboarding"]
|
|
1860
1860
|
})
|
|
1861
1861
|
]),
|
|
1862
|
-
|
|
1862
|
+
_chunk744JXTDPcjs.columnFromTicketStatus.call(void 0, "TECH_REQUIRED", [
|
|
1863
1863
|
ticket("tk-1049", "Acrobat Pro for Maya", "TECH_REQUIRED", {
|
|
1864
1864
|
ticketNumber: "1049",
|
|
1865
1865
|
agent: "fae",
|
|
@@ -1883,7 +1883,7 @@ function buildTicketsBoardFixture(cast) {
|
|
|
1883
1883
|
escalatedByUser: true
|
|
1884
1884
|
})
|
|
1885
1885
|
]),
|
|
1886
|
-
|
|
1886
|
+
_chunk744JXTDPcjs.columnFromTicketStatus.call(void 0, "ON_HOLD", [
|
|
1887
1887
|
ticket("tk-1046", "Replace the conference room display", "ON_HOLD", {
|
|
1888
1888
|
ticketNumber: "1046",
|
|
1889
1889
|
organizationName: _chunkFDZOE5TLcjs.DEMO_ORGANIZATIONS.acme.name,
|
|
@@ -1892,7 +1892,7 @@ function buildTicketsBoardFixture(cast) {
|
|
|
1892
1892
|
activity: { kind: "waiting-external" }
|
|
1893
1893
|
})
|
|
1894
1894
|
]),
|
|
1895
|
-
|
|
1895
|
+
_chunk744JXTDPcjs.columnFromTicketStatus.call(void 0,
|
|
1896
1896
|
"RESOLVED",
|
|
1897
1897
|
[
|
|
1898
1898
|
ticket("tk-1048", "Slow laptop", "RESOLVED", {
|
|
@@ -1928,7 +1928,7 @@ function TicketsBoardScreen({ compact = false }) {
|
|
|
1928
1928
|
const cast = _chunkLHV2R6QUcjs.useProductDemoCast.call(void 0, );
|
|
1929
1929
|
const board = _react.useMemo.call(void 0, () => buildTicketsBoardFixture(cast), [cast]);
|
|
1930
1930
|
const columns = compact ? board.filter((column) => column.id !== "ON_HOLD") : board;
|
|
1931
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg p-[var(--spacing-system-m)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1931
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg p-[var(--spacing-system-m)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk744JXTDPcjs.Board, { columns, onChange: noop, initialCollapsed: compact ? void 0 : FOLDED }) });
|
|
1932
1932
|
}
|
|
1933
1933
|
|
|
1934
1934
|
|
|
@@ -126,6 +126,34 @@ export interface SlidingSidebarConfig {
|
|
|
126
126
|
position?: 'left' | 'right';
|
|
127
127
|
className?: string;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* `NavigationSidebarConfig.resizable`: the user drags the expanded sidebar's
|
|
131
|
+
* right edge on desktop (`lg` and up). The 56px rail is not resizable, nor are
|
|
132
|
+
* the tablet overlay and the burger menu; the overlay opens to the chosen width.
|
|
133
|
+
*/
|
|
134
|
+
export interface NavigationSidebarResizeConfig {
|
|
135
|
+
/**
|
|
136
|
+
* Narrowest expanded width, in px. Raised to 141px when lower: the rows read
|
|
137
|
+
* 140px and up as expanded (`@[140px]/of-nav-sidebar`).
|
|
138
|
+
*/
|
|
139
|
+
minWidth: number;
|
|
140
|
+
/** Widest expanded width, in px. Also kept to the room there is (`minContentWidth`). */
|
|
141
|
+
maxWidth: number;
|
|
142
|
+
/**
|
|
143
|
+
* Px of the row the content beside the sidebar always keeps, so a wide sidebar
|
|
144
|
+
* cannot crowd the page out of a narrow desktop window. Default 720, the lib's
|
|
145
|
+
* `content-md` breakpoint.
|
|
146
|
+
*/
|
|
147
|
+
minContentWidth?: number;
|
|
148
|
+
/**
|
|
149
|
+
* `localStorage` key for the width the user chose: `{ size }` under
|
|
150
|
+
* `<storageKey>:chosen` (see `useResizablePanelSize`). Only a drag or a key
|
|
151
|
+
* press on the handle writes it, never the default or a clamped width; a double
|
|
152
|
+
* click removes it. Omit to keep the choice for the mount only. A host that seeds
|
|
153
|
+
* `NAVIGATION_SIDEBAR_WIDTH_VAR` before first paint reads the same entry.
|
|
154
|
+
*/
|
|
155
|
+
storageKey?: string;
|
|
156
|
+
}
|
|
129
157
|
/**
|
|
130
158
|
* Configuration for the navigation sidebar component
|
|
131
159
|
*/
|
|
@@ -253,6 +281,14 @@ export interface NavigationSidebarConfig {
|
|
|
253
281
|
* chat search in `sectionSlot`.
|
|
254
282
|
*/
|
|
255
283
|
revealSignal?: number;
|
|
284
|
+
/**
|
|
285
|
+
* Let the user resize the expanded sidebar on desktop: a drag handle astride
|
|
286
|
+
* its right edge (the grip the Mingo chat drawer had), arrow keys, Home and
|
|
287
|
+
* End on it, a double click back to the default. The default stays
|
|
288
|
+
* `expandedWidth` (grouped) or 224px (flat); both variants. Omitted: the fixed
|
|
289
|
+
* widths, as before.
|
|
290
|
+
*/
|
|
291
|
+
resizable?: NavigationSidebarResizeConfig;
|
|
256
292
|
}
|
|
257
293
|
/** What a slot render function is told about the place it is drawn in. */
|
|
258
294
|
export interface NavigationSidebarSlotState {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/types/navigation.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/types/navigation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { forwardRef, type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from 'react';
|
|
4
|
+
import { useClippedLabelTooltip } from '../../hooks/ui/use-clipped-label-tooltip';
|
|
4
5
|
import { cn } from '../../utils/cn';
|
|
5
6
|
import { MediaSkeleton, TextLineSkeleton } from '../loading/unified-skeleton';
|
|
6
7
|
import { BUTTON_KIND_CLASS, Button } from '../ui/button';
|
|
8
|
+
import { FloatingTooltip } from '../ui/floating-tooltip';
|
|
7
9
|
import { LoadingItems, loadingItemProps, useLoadingScope } from '../ui/loading-scope';
|
|
8
10
|
import { ScrollFadeOverlay, useScrollFade } from '../ui/scroll-fade';
|
|
9
11
|
|
|
@@ -157,6 +159,8 @@ const ChatListItem = forwardRef<HTMLButtonElement, ChatListItemProps>(
|
|
|
157
159
|
ref,
|
|
158
160
|
) => {
|
|
159
161
|
const loading = useLoadingScope() || loadingProp;
|
|
162
|
+
// A title the list clips: its full text in a tooltip over it, only while clipped and where a pointer can hover.
|
|
163
|
+
const { ref: titleRef, enabled: titleTooltip } = useClippedLabelTooltip<HTMLSpanElement>(title);
|
|
160
164
|
const content = (
|
|
161
165
|
<>
|
|
162
166
|
<span className="flex min-w-0 flex-1 flex-col">
|
|
@@ -165,11 +169,20 @@ const ChatListItem = forwardRef<HTMLButtonElement, ChatListItemProps>(
|
|
|
165
169
|
{loading ? (
|
|
166
170
|
<TextLineSkeleton type="h4" className={SKELETON_TITLE_WIDTHS[index % SKELETON_TITLE_WIDTHS.length]} />
|
|
167
171
|
) : (
|
|
168
|
-
<
|
|
169
|
-
|
|
172
|
+
<FloatingTooltip
|
|
173
|
+
content={title}
|
|
174
|
+
side="top"
|
|
175
|
+
as="span"
|
|
176
|
+
disabled={!titleTooltip}
|
|
177
|
+
triggerClassName="min-w-0 flex-1"
|
|
170
178
|
>
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
<span
|
|
180
|
+
ref={titleRef}
|
|
181
|
+
className={cn('block min-w-0 truncate text-h4', active ? 'text-ods-accent' : 'text-ods-text-primary')}
|
|
182
|
+
>
|
|
183
|
+
{title}
|
|
184
|
+
</span>
|
|
185
|
+
</FloatingTooltip>
|
|
173
186
|
)}
|
|
174
187
|
</span>
|
|
175
188
|
{subtitle != null &&
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
4
4
|
import type { ReactNode } from 'react';
|
|
5
|
+
import { useClippedLabelTooltip } from '../../hooks/ui/use-clipped-label-tooltip';
|
|
5
6
|
import { cn } from '../../utils';
|
|
6
7
|
import { Chevron02DownIcon } from '../icons-v2-generated';
|
|
7
8
|
import { ActionsMenuDropdown, type ActionsMenuGroup, type ActionsMenuItem } from '../ui/actions-menu';
|
|
9
|
+
import { FloatingTooltip } from '../ui/floating-tooltip';
|
|
8
10
|
import { SquareAvatar } from '../ui/square-avatar';
|
|
9
11
|
import { UnreadCountBadge, UnreadDot } from './unread-dot';
|
|
10
12
|
|
|
@@ -124,6 +126,11 @@ export function AccountPopover({
|
|
|
124
126
|
className,
|
|
125
127
|
}: AccountPopoverProps) {
|
|
126
128
|
const unread = items.some(entry => entry.type !== 'divider' && (entry.count ?? 0) > 0);
|
|
129
|
+
// The name and subtitle a narrow sidebar clips: their full text in a tooltip
|
|
130
|
+
// over them, only while clipped and where a pointer can hover. The rail's
|
|
131
|
+
// tooltip is the trigger's `title`.
|
|
132
|
+
const { ref: nameRef, enabled: nameTooltip } = useClippedLabelTooltip<HTMLSpanElement>(name);
|
|
133
|
+
const { ref: subtitleRef, enabled: subtitleTooltip } = useClippedLabelTooltip<HTMLSpanElement>(subtitle);
|
|
127
134
|
const [open = false, setOpen] = useControllableState({
|
|
128
135
|
prop: openProp,
|
|
129
136
|
defaultProp: false,
|
|
@@ -182,14 +189,36 @@ export function AccountPopover({
|
|
|
182
189
|
{/* The chevron follows the name, so it reads as this row's menu and not
|
|
183
190
|
as one more of the buttons a host sets at the row's end. */}
|
|
184
191
|
<span className="flex min-w-0 items-center gap-[var(--spacing-system-xxs)]">
|
|
185
|
-
<
|
|
192
|
+
<FloatingTooltip
|
|
193
|
+
content={name}
|
|
194
|
+
side="top"
|
|
195
|
+
as="span"
|
|
196
|
+
disabled={collapsed || !nameTooltip}
|
|
197
|
+
triggerClassName="min-w-0"
|
|
198
|
+
>
|
|
199
|
+
<span ref={nameRef} className="block truncate text-ods-text-primary text-h4">
|
|
200
|
+
{name}
|
|
201
|
+
</span>
|
|
202
|
+
</FloatingTooltip>
|
|
186
203
|
<Chevron02DownIcon
|
|
187
204
|
size={16}
|
|
188
205
|
className="shrink-0 text-ods-text-secondary transition-transform duration-200 group-data-[state=open]/account:rotate-180"
|
|
189
206
|
aria-hidden="true"
|
|
190
207
|
/>
|
|
191
208
|
</span>
|
|
192
|
-
{subtitle &&
|
|
209
|
+
{subtitle && (
|
|
210
|
+
<FloatingTooltip
|
|
211
|
+
content={subtitle}
|
|
212
|
+
side="top"
|
|
213
|
+
as="span"
|
|
214
|
+
disabled={collapsed || !subtitleTooltip}
|
|
215
|
+
triggerClassName="min-w-0"
|
|
216
|
+
>
|
|
217
|
+
<span ref={subtitleRef} className="block truncate text-ods-text-secondary text-code">
|
|
218
|
+
{subtitle}
|
|
219
|
+
</span>
|
|
220
|
+
</FloatingTooltip>
|
|
221
|
+
)}
|
|
193
222
|
</span>
|
|
194
223
|
</button>
|
|
195
224
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { useIsomorphicLayoutEffect } from '../../hooks/ui/use-isomorphic-layout-effect';
|
|
14
14
|
import { breakpoints, useMediaQuery } from '../../hooks/ui/use-media-query';
|
|
15
15
|
import { cn } from '../../utils/cn';
|
|
16
|
-
import {
|
|
16
|
+
import { PanelResizeGrip } from '../ui/panel-resize-handle';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* - `docked`: a column beside the content, resizable.
|
|
@@ -523,12 +523,7 @@ function SidePanelResizeHandle({ state, label, controls }: SidePanelResizeHandle
|
|
|
523
523
|
onKeyDown={handleKeyDown}
|
|
524
524
|
className="group absolute inset-y-0 left-0 z-10 flex w-4 -translate-x-1/2 cursor-col-resize touch-none select-none items-center justify-center outline-none"
|
|
525
525
|
>
|
|
526
|
-
<
|
|
527
|
-
aria-hidden
|
|
528
|
-
className="flex h-8 w-4 items-center justify-center rounded-sm border border-ods-border bg-ods-card text-ods-text-secondary transition-colors group-hover:border-ods-border-hover group-focus-visible:border-ods-accent group-focus-visible:text-ods-accent"
|
|
529
|
-
>
|
|
530
|
-
<Menu01Icon size={12} />
|
|
531
|
-
</span>
|
|
526
|
+
<PanelResizeGrip />
|
|
532
527
|
</div>
|
|
533
528
|
);
|
|
534
529
|
}
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { cloneElement, isValidElement, type MouseEvent, type ReactNode, useId, useState } from 'react';
|
|
4
4
|
import Link from '../../embed-shims/next-link';
|
|
5
|
+
import { useClippedLabelTooltip } from '../../hooks/ui/use-clipped-label-tooltip';
|
|
5
6
|
import type { NavigationSidebarItem } from '../../types/navigation';
|
|
6
7
|
import { cn } from '../../utils';
|
|
7
8
|
import { UnifiedSkeleton } from '../loading/unified-skeleton';
|
|
9
|
+
import { FloatingTooltip } from '../ui/floating-tooltip';
|
|
8
10
|
import { NavigationItemBadge } from './navigation-item-badge';
|
|
9
11
|
import { UnreadDot } from './unread-dot';
|
|
10
12
|
|
|
@@ -150,8 +152,15 @@ function RowEnd({ count }: { count: number }) {
|
|
|
150
152
|
return count > 0 ? <CountPill count={count} className="ml-auto" /> : null;
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
/**
|
|
156
|
+
* The row's label column. A label the expanded sidebar clips (a narrow width,
|
|
157
|
+
* a long label) shows its full text in a tooltip over it, as `TruncateText`
|
|
158
|
+
* offers it — only while it IS clipped, and only where a pointer can hover.
|
|
159
|
+
* The rail (`showLabel` false) has its own: the row's `title`.
|
|
160
|
+
*/
|
|
161
|
+
function RowLabel({ item, showLabel = true }: { item: NavigationSidebarItem; showLabel?: boolean }) {
|
|
154
162
|
const unreadCount = item.unreadCount ?? 0;
|
|
163
|
+
const { ref: labelRef, enabled: labelTooltip } = useClippedLabelTooltip<HTMLSpanElement>(item.label);
|
|
155
164
|
return (
|
|
156
165
|
<span
|
|
157
166
|
className={cn(
|
|
@@ -159,7 +168,17 @@ function RowLabel({ item }: { item: NavigationSidebarItem }) {
|
|
|
159
168
|
EXPANDED_ONLY,
|
|
160
169
|
)}
|
|
161
170
|
>
|
|
162
|
-
<
|
|
171
|
+
<FloatingTooltip
|
|
172
|
+
content={item.label}
|
|
173
|
+
side="top"
|
|
174
|
+
as="span"
|
|
175
|
+
disabled={!showLabel || !labelTooltip}
|
|
176
|
+
triggerClassName="min-w-0"
|
|
177
|
+
>
|
|
178
|
+
<span ref={labelRef} className="block min-w-0 truncate text-h4">
|
|
179
|
+
{item.label}
|
|
180
|
+
</span>
|
|
181
|
+
</FloatingTooltip>
|
|
163
182
|
{item.badge && <NavigationItemBadge label={item.badge} compact />}
|
|
164
183
|
<RowEnd count={unreadCount} />
|
|
165
184
|
</span>
|
|
@@ -204,7 +223,7 @@ function GroupedLeafRow({
|
|
|
204
223
|
const content = (
|
|
205
224
|
<>
|
|
206
225
|
<RowIcon item={item} size={20} className={lit ? 'text-ods-accent' : idleIcon('row')} />
|
|
207
|
-
<RowLabel item={item} />
|
|
226
|
+
<RowLabel item={item} showLabel={showLabel} />
|
|
208
227
|
</>
|
|
209
228
|
);
|
|
210
229
|
const shared = {
|
|
@@ -248,6 +267,8 @@ function GroupedChildRow({
|
|
|
248
267
|
}) {
|
|
249
268
|
const name = accessibleName(item);
|
|
250
269
|
const lit = isActive && !disabled;
|
|
270
|
+
// The clipped label's tooltip, as `RowLabel` offers it.
|
|
271
|
+
const { ref: labelRef, enabled: labelTooltip } = useClippedLabelTooltip<HTMLSpanElement>(item.label);
|
|
251
272
|
const className = cn(
|
|
252
273
|
// The icon column flush, under the parent's icon at both widths.
|
|
253
274
|
'group/nav-child relative flex h-11 w-full items-stretch gap-[var(--spacing-system-xxs)] rounded-md text-left',
|
|
@@ -276,7 +297,17 @@ function GroupedChildRow({
|
|
|
276
297
|
!lit && !disabled && isPending && 'after:opacity-100',
|
|
277
298
|
)}
|
|
278
299
|
>
|
|
279
|
-
<
|
|
300
|
+
<FloatingTooltip
|
|
301
|
+
content={item.label}
|
|
302
|
+
side="top"
|
|
303
|
+
as="span"
|
|
304
|
+
disabled={!showLabel || !labelTooltip}
|
|
305
|
+
triggerClassName="min-w-0"
|
|
306
|
+
>
|
|
307
|
+
<span ref={labelRef} className="block min-w-0 truncate text-h4">
|
|
308
|
+
{item.label}
|
|
309
|
+
</span>
|
|
310
|
+
</FloatingTooltip>
|
|
280
311
|
{item.badge && <NavigationItemBadge label={item.badge} compact />}
|
|
281
312
|
<RowEnd count={item.unreadCount ?? 0} />
|
|
282
313
|
</span>
|
|
@@ -365,7 +396,7 @@ function GroupedGroup({
|
|
|
365
396
|
)}
|
|
366
397
|
>
|
|
367
398
|
<RowIcon item={item} size={20} className={lit ? 'text-ods-accent' : idleIcon('row')} />
|
|
368
|
-
<RowLabel item={item} />
|
|
399
|
+
<RowLabel item={item} showLabel={showLabel} />
|
|
369
400
|
</button>
|
|
370
401
|
<div
|
|
371
402
|
id={groupDomId}
|
|
@@ -517,7 +548,7 @@ export function NavigationSidebarActionRow({
|
|
|
517
548
|
const content = (
|
|
518
549
|
<>
|
|
519
550
|
<RowIcon item={entry} size={20} className={lit || (outline && !disabled) ? 'text-ods-accent' : idleIcon('row')} />
|
|
520
|
-
<RowLabel item={entry} />
|
|
551
|
+
<RowLabel item={entry} showLabel={!minimized} />
|
|
521
552
|
</>
|
|
522
553
|
);
|
|
523
554
|
const shared = { className: classes, title: minimized ? name : undefined, 'aria-label': name };
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { cloneElement, memo, type ReactElement, type ReactNode, type MouseEvent } from 'react';
|
|
4
4
|
import Link from '../../embed-shims/next-link';
|
|
5
|
+
import { useClippedLabelTooltip } from '../../hooks/ui/use-clipped-label-tooltip';
|
|
5
6
|
import type { NavigationSidebarItem } from '../../types/navigation';
|
|
6
7
|
import { cn } from '../../utils';
|
|
7
8
|
import { UnifiedSkeleton } from '../loading/unified-skeleton';
|
|
8
9
|
import { BUTTON_KIND_CLASS, Button } from '../ui/button';
|
|
10
|
+
import { FloatingTooltip } from '../ui/floating-tooltip';
|
|
9
11
|
import { useLoadingScope } from '../ui/loading-scope';
|
|
10
12
|
import { NavigationItemBadge } from './navigation-item-badge';
|
|
11
13
|
import { UnreadDot } from './unread-dot';
|
|
@@ -76,6 +78,11 @@ function LoadedNavigationSidebarItemButton({
|
|
|
76
78
|
// The accessible name carries the stamp — "Devices (Beta)" — because `aria-label`
|
|
77
79
|
// replaces the content; the rail's tooltip is the same string.
|
|
78
80
|
const name = item.badge ? `${item.label} (${item.badge})` : item.label;
|
|
81
|
+
// A label the expanded sidebar clips (a narrow width, a long label): its full
|
|
82
|
+
// text in a tooltip over it, as `TruncateText` offers it — only while it IS
|
|
83
|
+
// clipped, since a label that fits would only repeat itself, and only where a
|
|
84
|
+
// pointer can hover. The rail's tooltip is the row's `title` below.
|
|
85
|
+
const { ref: labelRef, enabled: labelTooltip } = useClippedLabelTooltip<HTMLSpanElement>(item.label);
|
|
79
86
|
|
|
80
87
|
const content: ReactNode = (
|
|
81
88
|
<>
|
|
@@ -98,7 +105,17 @@ function LoadedNavigationSidebarItemButton({
|
|
|
98
105
|
)}
|
|
99
106
|
aria-hidden={!showLabel}
|
|
100
107
|
>
|
|
101
|
-
<
|
|
108
|
+
<FloatingTooltip
|
|
109
|
+
content={item.label}
|
|
110
|
+
side="top"
|
|
111
|
+
as="span"
|
|
112
|
+
disabled={!showLabel || !labelTooltip}
|
|
113
|
+
triggerClassName="min-w-0"
|
|
114
|
+
>
|
|
115
|
+
<span ref={labelRef} className="block min-w-0 truncate text-h4">
|
|
116
|
+
{item.label}
|
|
117
|
+
</span>
|
|
118
|
+
</FloatingTooltip>
|
|
102
119
|
{item.badge && <NavigationItemBadge label={item.badge} className="ml-[var(--spacing-system-xs)] shrink-0" />}
|
|
103
120
|
</span>
|
|
104
121
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
-
import type { CSSProperties, MouseEvent, ReactNode } from 'react';
|
|
4
|
+
import type { CSSProperties, MouseEvent, ReactNode, RefObject } from 'react';
|
|
5
5
|
import { useIsHydrated } from '../../hooks/ui/use-is-hydrated';
|
|
6
6
|
import { useIsomorphicLayoutEffect } from '../../hooks/ui/use-isomorphic-layout-effect';
|
|
7
7
|
import { useLocalStorage } from '../../hooks/ui/use-local-storage';
|
|
8
8
|
import { useLgUp, useMdUp } from '../../hooks/ui/use-media-query';
|
|
9
|
+
import { useResizablePanelSize } from '../../hooks/ui/use-resizable-panel-size';
|
|
9
10
|
import type { NavigationSidebarConfig, NavigationSidebarItem } from '../../types/navigation';
|
|
10
11
|
import { cn } from '../../utils';
|
|
12
|
+
import { PanelResizeGrip, PanelResizeHandle } from '../ui/panel-resize-handle';
|
|
11
13
|
import { NAVIGATION_SIDEBAR_ATTRIBUTE } from './app-layout-context';
|
|
12
14
|
import {
|
|
13
15
|
NavigationSidebarGroupedEntries,
|
|
@@ -24,6 +26,12 @@ const MINIMIZED_WIDTH = 56; // 3.5rem = 56px
|
|
|
24
26
|
const EXPANDED_WIDTH = 224; // 14rem = 224px — the default; a grouped config may set its own
|
|
25
27
|
/** The narrowest custom `expandedWidth`: the rows read 140px and up as expanded. */
|
|
26
28
|
const MIN_CUSTOM_EXPANDED_WIDTH = 141;
|
|
29
|
+
/**
|
|
30
|
+
* Px of its row a resizable sidebar leaves to the content beside it
|
|
31
|
+
* (`NavigationSidebarResizeConfig.minContentWidth`): the `content-md`
|
|
32
|
+
* breakpoint, under which page content lays out for a phone.
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_MIN_CONTENT_WIDTH = 720;
|
|
27
35
|
const STORAGE_KEY = 'of.navigationSidebar.minimized';
|
|
28
36
|
|
|
29
37
|
/**
|
|
@@ -146,6 +154,27 @@ const SIDEBAR_TABLET_WIDTH = {
|
|
|
146
154
|
customOverlay: 'md:w-[var(--of-navigation-sidebar-expanded-width)]',
|
|
147
155
|
} as const;
|
|
148
156
|
|
|
157
|
+
/**
|
|
158
|
+
* The width of the sidebar's row — its parent, the room it shares with the
|
|
159
|
+
* content — for the resize clamp. 0 until measured, and when there is nothing to
|
|
160
|
+
* measure (not resizable, no parent, the server).
|
|
161
|
+
*/
|
|
162
|
+
function useRowWidth(asideRef: RefObject<HTMLElement | null>, enabled: boolean): number {
|
|
163
|
+
const [width, setWidth] = useState(0);
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
const row = enabled ? asideRef.current?.parentElement : null;
|
|
166
|
+
if (!row) return undefined;
|
|
167
|
+
const update = () => setWidth(row.clientWidth);
|
|
168
|
+
update();
|
|
169
|
+
// An environment without ResizeObserver (jsdom in a consumer's tests) measures once.
|
|
170
|
+
if (typeof ResizeObserver === 'undefined') return undefined;
|
|
171
|
+
const observer = new ResizeObserver(update);
|
|
172
|
+
observer.observe(row);
|
|
173
|
+
return () => observer.disconnect();
|
|
174
|
+
}, [asideRef, enabled]);
|
|
175
|
+
return width;
|
|
176
|
+
}
|
|
177
|
+
|
|
149
178
|
/** A click the browser will resolve itself — new tab, new window, middle button. */
|
|
150
179
|
export const isModifiedClick = (event?: MouseEvent): boolean =>
|
|
151
180
|
!!event && (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0);
|
|
@@ -255,18 +284,74 @@ export function NavigationSidebar({
|
|
|
255
284
|
|
|
256
285
|
// A grouped config's own expanded width (`expandedWidth`); `null` = the
|
|
257
286
|
// default 224px through the literal classes, exactly as before.
|
|
258
|
-
const
|
|
287
|
+
const configExpandedWidth =
|
|
259
288
|
config.variant === 'grouped' && config.expandedWidth !== undefined
|
|
260
289
|
? Math.max(config.expandedWidth, MIN_CUSTOM_EXPANDED_WIDTH)
|
|
261
290
|
: null;
|
|
262
|
-
|
|
291
|
+
|
|
292
|
+
// `config.resizable`: the expanded width is the user's — dragged or stepped on
|
|
293
|
+
// the handle below, kept under the config's storage key — and the config width
|
|
294
|
+
// is where it starts. Clamped to the config's bounds and to the row, so the
|
|
295
|
+
// content beside the rail keeps `minContentWidth`. Not resizable: the config
|
|
296
|
+
// width, and the hook reads and writes nothing.
|
|
297
|
+
const resize = config.resizable;
|
|
298
|
+
const asideRef = useRef<HTMLElement>(null);
|
|
299
|
+
const rowWidth = useRowWidth(asideRef, resize !== undefined);
|
|
300
|
+
const resizeMinWidth = Math.max(resize?.minWidth ?? MIN_CUSTOM_EXPANDED_WIDTH, MIN_CUSTOM_EXPANDED_WIDTH);
|
|
301
|
+
const {
|
|
302
|
+
size: chosenExpandedWidth,
|
|
303
|
+
setSize: setChosenExpandedWidth,
|
|
304
|
+
resetSize: resetChosenExpandedWidth,
|
|
305
|
+
clampSize: clampExpandedWidth,
|
|
306
|
+
} = useResizablePanelSize({
|
|
307
|
+
enabled: resize !== undefined,
|
|
308
|
+
minSize: resizeMinWidth,
|
|
309
|
+
maxSize: resize?.maxWidth ?? Number.POSITIVE_INFINITY,
|
|
310
|
+
defaultSize: configExpandedWidth ?? EXPANDED_WIDTH,
|
|
311
|
+
available: rowWidth,
|
|
312
|
+
reserve: resize?.minContentWidth ?? DEFAULT_MIN_CONTENT_WIDTH,
|
|
313
|
+
storageKey: resize?.storageKey,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// The desktop width — what the effect below publishes. The chosen width may
|
|
317
|
+
// be used here as soon as it is known: an effect never runs into the SSR HTML.
|
|
318
|
+
const expandedWidth = resize !== undefined ? chosenExpandedWidth : (configExpandedWidth ?? EXPANDED_WIDTH);
|
|
319
|
+
// The width in the MARKUP — the inline custom property on the rail and its
|
|
320
|
+
// tablet slot, which the tablet overlay opens to and the desktop rule falls
|
|
321
|
+
// back on, and the handle's `aria-valuenow`: the chosen width only once
|
|
322
|
+
// hydrated. The server could not read it, and a first client render that
|
|
323
|
+
// differs is a hydration mismatch, which React reports and leaves in the DOM.
|
|
324
|
+
// Until then the config width stands, as for a sidebar that is not resizable;
|
|
325
|
+
// on desktop the seeded width shows throughout, so nothing moves.
|
|
326
|
+
const markupExpandedWidth = hydrated ? chosenExpandedWidth : (configExpandedWidth ?? EXPANDED_WIDTH);
|
|
327
|
+
const customExpandedWidth = resize !== undefined ? markupExpandedWidth : configExpandedWidth;
|
|
263
328
|
const expandedWidthStyle =
|
|
264
329
|
customExpandedWidth === null ? undefined : ({ [EXPANDED_WIDTH_VAR]: `${customExpandedWidth}px` } as CSSProperties);
|
|
265
330
|
|
|
331
|
+
// A drag moves the rail's own width property on every pointer move and marks
|
|
332
|
+
// the rail (`data-resizing`, read by a class on it) so its width transition
|
|
333
|
+
// does not trail the pointer; the choice is committed once, on release, which
|
|
334
|
+
// also lifts the mark. Neither write concerns hydration: both run on the
|
|
335
|
+
// client only, once the user has the handle.
|
|
336
|
+
const dragExpandedWidth = useCallback((next: number) => {
|
|
337
|
+
const aside = asideRef.current;
|
|
338
|
+
if (!aside) return;
|
|
339
|
+
aside.setAttribute('data-resizing', '');
|
|
340
|
+
aside.style.setProperty(NAVIGATION_SIDEBAR_WIDTH_VAR, `${Math.round(next)}px`);
|
|
341
|
+
}, []);
|
|
342
|
+
const commitExpandedWidth = useCallback(
|
|
343
|
+
(next: number) => {
|
|
344
|
+
asideRef.current?.removeAttribute('data-resizing');
|
|
345
|
+
setChosenExpandedWidth(next);
|
|
346
|
+
},
|
|
347
|
+
[setChosenExpandedWidth],
|
|
348
|
+
);
|
|
349
|
+
|
|
266
350
|
// A new expanded width (the host swapped configs — e.g. a placeholder for
|
|
267
|
-
// the grouped tree
|
|
268
|
-
//
|
|
269
|
-
//
|
|
351
|
+
// the grouped tree; a resize committed, stepped or reset on the handle) is a
|
|
352
|
+
// different sidebar, not a toggle: it snaps instead of animating. The
|
|
353
|
+
// transition is dropped in the same commit that moves the width and comes
|
|
354
|
+
// back a frame later (the effect below).
|
|
270
355
|
const [widthFor, setWidthFor] = useState(expandedWidth);
|
|
271
356
|
if (widthFor !== expandedWidth) {
|
|
272
357
|
setWidthFor(expandedWidth);
|
|
@@ -447,7 +532,6 @@ export function NavigationSidebar({
|
|
|
447
532
|
// On the rail, not on `<html>` where the seed sits: the rail is its only reader,
|
|
448
533
|
// and an inherited custom property on the root made WebKit restyle the whole
|
|
449
534
|
// document on every toggle. Its own value overrides the inherited seed.
|
|
450
|
-
const asideRef = useRef<HTMLElement>(null);
|
|
451
535
|
useIsomorphicLayoutEffect(() => {
|
|
452
536
|
asideRef.current?.style.setProperty(NAVIGATION_SIDEBAR_WIDTH_VAR, sidebarWidth);
|
|
453
537
|
}, [sidebarWidth]);
|
|
@@ -555,6 +639,9 @@ export function NavigationSidebar({
|
|
|
555
639
|
? SIDEBAR_TABLET_WIDTH.overlay
|
|
556
640
|
: SIDEBAR_TABLET_WIDTH.customOverlay,
|
|
557
641
|
transitionsEnabled && widthTransition,
|
|
642
|
+
// A drag on the resize handle in progress: the width follows the
|
|
643
|
+
// pointer, with no transition trailing it (`dragExpandedWidth`).
|
|
644
|
+
'data-[resizing]:transition-none',
|
|
558
645
|
// Snaps where its width moves the content: the desktop rail, and the
|
|
559
646
|
// tablet overlay too when it pushes (its slot above snaps with it).
|
|
560
647
|
!animateWidth && (pushOnTablet ? 'transition-none' : 'lg:transition-none'),
|
|
@@ -632,6 +719,28 @@ export function NavigationSidebar({
|
|
|
632
719
|
onToggle={handleToggle}
|
|
633
720
|
compact={grouped}
|
|
634
721
|
/>
|
|
722
|
+
|
|
723
|
+
{/* The resize handle (`config.resizable`), astride the rail's right edge —
|
|
724
|
+
the grip the Mingo chat drawer had — on desktop while expanded: the
|
|
725
|
+
56px rail has nothing to resize, and below `lg` the width is the
|
|
726
|
+
tablet's. The 24px track straddles the border, half of it over the
|
|
727
|
+
content's edge; the grip marks the border as draggable. */}
|
|
728
|
+
{resize !== undefined && !minimized && (
|
|
729
|
+
<PanelResizeHandle
|
|
730
|
+
side="left"
|
|
731
|
+
variant="inLayout"
|
|
732
|
+
size={markupExpandedWidth}
|
|
733
|
+
minSize={resizeMinWidth}
|
|
734
|
+
maxSize={clampExpandedWidth(Number.POSITIVE_INFINITY)}
|
|
735
|
+
clampSize={clampExpandedWidth}
|
|
736
|
+
onSize={commitExpandedWidth}
|
|
737
|
+
onDrag={dragExpandedWidth}
|
|
738
|
+
onReset={resetChosenExpandedWidth}
|
|
739
|
+
ariaLabel="Resize navigation sidebar"
|
|
740
|
+
className="inset-y-0 hidden w-6 -translate-x-1/2 justify-center pl-0 lg:flex"
|
|
741
|
+
grip={<PanelResizeGrip />}
|
|
742
|
+
/>
|
|
743
|
+
)}
|
|
635
744
|
</aside>
|
|
636
745
|
</>
|
|
637
746
|
);
|