@servicetitan/navigation 14.3.0 → 14.5.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/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +30 -11
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +1 -1
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js +1 -1
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js.map +1 -1
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.d.ts.map +1 -1
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js +69 -107
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js.map +1 -1
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less +70 -127
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +2 -0
- package/dist/utils/__tests__/catalog-groups.test.d.ts +2 -0
- package/dist/utils/__tests__/catalog-groups.test.d.ts.map +1 -0
- package/dist/utils/__tests__/side-nav.test.d.ts +2 -0
- package/dist/utils/__tests__/side-nav.test.d.ts.map +1 -0
- package/dist/utils/catalog-groups.d.ts +11 -0
- package/dist/utils/catalog-groups.d.ts.map +1 -0
- package/dist/utils/catalog-groups.js +66 -0
- package/dist/utils/catalog-groups.js.map +1 -0
- package/dist/utils/side-nav.d.ts +17 -0
- package/dist/utils/side-nav.d.ts.map +1 -1
- package/dist/utils/side-nav.js +32 -0
- package/dist/utils/side-nav.js.map +1 -1
- package/package.json +2 -2
- package/src/components/titan-layout/__tests__/navigation-catalog-reset.test.tsx +7 -3
- package/src/components/titan-layout/layout-sidebar.module.less +1 -1
- package/src/components/titan-layout/layout-sidebar.tsx +34 -10
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.tsx +1 -1
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less +70 -127
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +2 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.tsx +107 -134
- package/src/utils/__tests__/catalog-groups.test.ts +97 -0
- package/src/utils/__tests__/side-nav.test.ts +77 -0
- package/src/utils/catalog-groups.ts +57 -0
- package/src/utils/side-nav.ts +42 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout-sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/titan-layout/layout-sidebar.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAY,EAAE,EAAY,YAAY,
|
|
1
|
+
{"version":3,"file":"layout-sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/titan-layout/layout-sidebar.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAY,EAAE,EAAY,YAAY,EAAuC,MAAM,OAAO,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAyB,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAQvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAcrD,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC;IAErB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAEhC,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACrC,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC;IAC/C,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3C,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvD,oBAAoB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5D,qBAAqB,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxE;AAED,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA8KhD,CAAC"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button, Divider, Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';
|
|
2
|
+
import { Button, Divider, Flex, Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';
|
|
3
3
|
import SvgClose from '@servicetitan/anvil2/assets/icons/material/round/close.svg';
|
|
4
4
|
import SvgCollapseAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_less.svg';
|
|
5
5
|
import SvgExpandAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_more.svg';
|
|
6
6
|
import SvgCollapse from '@servicetitan/anvil2/assets/icons/st/gnav_menu_collapse.svg';
|
|
7
7
|
import SvgExpand from '@servicetitan/anvil2/assets/icons/st/gnav_menu_expand.svg';
|
|
8
8
|
import classNames from 'classnames';
|
|
9
|
-
import { Children, Fragment, isValidElement } from 'react';
|
|
9
|
+
import { Children, Fragment, isValidElement, useCallback, useRef } from 'react';
|
|
10
10
|
import { getModuleNotificationCount } from '../../utils/navigation-notifications';
|
|
11
|
-
import { getCounterTag, getSubmenuGroupTag } from '../../utils/side-nav';
|
|
11
|
+
import { getCounterTag, getModuleActiveMatcher, getModuleDestination, getSubmenuGroupTag } from '../../utils/side-nav';
|
|
12
12
|
import { LayoutPlacementContext, useTitanLayoutContext } from './layout-context';
|
|
13
13
|
import { InternalSideNavigationGroup, InternalSideNavigationGroupLink, InternalSideNavigationLink } from './layout-sidebar-links-internal';
|
|
14
14
|
import * as Styles from './layout-sidebar.module.less';
|
|
@@ -164,7 +164,8 @@ export const LayoutSidebar = ({ className, mobile, touchDevice, barExpanded, sub
|
|
|
164
164
|
/*#__PURE__*/ _jsx("div", {
|
|
165
165
|
className: Styles.divider
|
|
166
166
|
}),
|
|
167
|
-
/*#__PURE__*/ _jsx(
|
|
167
|
+
/*#__PURE__*/ _jsx(Flex, {
|
|
168
|
+
direction: "column",
|
|
168
169
|
className: Styles.toggleWrapper,
|
|
169
170
|
children: /*#__PURE__*/ _jsx(SideNavigationOptionsToggle, {
|
|
170
171
|
expanded: barExpanded,
|
|
@@ -182,6 +183,8 @@ LayoutSidebar.displayName = 'LayoutSidebar';
|
|
|
182
183
|
/** Side Navigation options toggle */ const SideNavigationOptionsToggle = ({ expanded, onExpandedChange })=>withTooltip(/*#__PURE__*/ _jsx(Button, {
|
|
183
184
|
appearance: "ghost",
|
|
184
185
|
size: "small",
|
|
186
|
+
flexGrow: 1,
|
|
187
|
+
justifyContent: "flex-start",
|
|
185
188
|
icon: expanded ? SvgCollapse : SvgExpand,
|
|
186
189
|
"data-cy": "navigation-left-options",
|
|
187
190
|
"data-pendo": "navigation-left-options",
|
|
@@ -190,18 +193,32 @@ LayoutSidebar.displayName = 'LayoutSidebar';
|
|
|
190
193
|
className: Styles.toggle,
|
|
191
194
|
onClick: ()=>onExpandedChange === null || onExpandedChange === void 0 ? void 0 : onExpandedChange(!expanded)
|
|
192
195
|
}), expanded ? 'Collapse Menu' : 'Expand Menu', {
|
|
193
|
-
placement: 'right'
|
|
196
|
+
placement: 'right',
|
|
197
|
+
pointerEventsNone: true
|
|
194
198
|
});
|
|
195
199
|
/** Side Navigation menu item */ const SideNavigationGroupItem = ({ item, onSubmenuOpen, onNavigationLinkClick, barExpanded, submenuOpened, navigationComponent, touchDevice })=>{
|
|
196
|
-
var _ref, _ref1;
|
|
200
|
+
var _item_isActive, _ref, _ref1;
|
|
197
201
|
var _item_submenu, _item_submenu1;
|
|
198
202
|
const { sidebar: { styles: { popoverContent } } } = useTitanLayoutContext();
|
|
199
203
|
const tag = getSubmenuGroupTag(item.submenu, getCounterTag(item.counter, item.tag));
|
|
204
|
+
const isActive = (_item_isActive = item.isActive) !== null && _item_isActive !== void 0 ? _item_isActive : getModuleActiveMatcher(item.to, item.submenu);
|
|
205
|
+
/*
|
|
206
|
+
* Some destinations (legacy monolith pages) never fire the route-change signal the popover
|
|
207
|
+
* would otherwise rely on to dismiss itself, leaving it stranded open over the loaded page.
|
|
208
|
+
* Closing explicitly on click, rather than waiting on navigation to settle, works everywhere.
|
|
209
|
+
*/ const popoverRef = useRef(null);
|
|
210
|
+
const handleSubmenuLinkClick = useCallback((itemId, submenuItemId)=>{
|
|
211
|
+
var _popoverRef_current;
|
|
212
|
+
(_popoverRef_current = popoverRef.current) === null || _popoverRef_current === void 0 ? void 0 : _popoverRef_current.closePopover();
|
|
213
|
+
onNavigationLinkClick === null || onNavigationLinkClick === void 0 ? void 0 : onNavigationLinkClick(itemId, submenuItemId);
|
|
214
|
+
}, [
|
|
215
|
+
onNavigationLinkClick
|
|
216
|
+
]);
|
|
200
217
|
return barExpanded ? /*#__PURE__*/ _jsx(InternalSideNavigationGroup, {
|
|
201
218
|
id: item.id,
|
|
202
|
-
to: item.to,
|
|
219
|
+
to: getModuleDestination(item.to, item.submenu),
|
|
203
220
|
title: item.title,
|
|
204
|
-
isActive:
|
|
221
|
+
isActive: isActive,
|
|
205
222
|
icon: item.icon,
|
|
206
223
|
iconActive: item.iconActive,
|
|
207
224
|
className: item.className,
|
|
@@ -217,6 +234,7 @@ LayoutSidebar.displayName = 'LayoutSidebar';
|
|
|
217
234
|
onNavigationLinkClick: onNavigationLinkClick
|
|
218
235
|
})
|
|
219
236
|
}) : /*#__PURE__*/ _jsxs(Popover, {
|
|
237
|
+
ref: popoverRef,
|
|
220
238
|
placement: "right-start",
|
|
221
239
|
openOnHover: !touchDevice,
|
|
222
240
|
delay: 200,
|
|
@@ -230,9 +248,9 @@ LayoutSidebar.displayName = 'LayoutSidebar';
|
|
|
230
248
|
...triggerProps,
|
|
231
249
|
children: /*#__PURE__*/ _jsx(InternalSideNavigationLink, {
|
|
232
250
|
id: item.id,
|
|
233
|
-
to: item.to,
|
|
251
|
+
to: getModuleDestination(item.to, item.submenu),
|
|
234
252
|
title: (_item_collapsedTitle = item.collapsedTitle) !== null && _item_collapsedTitle !== void 0 ? _item_collapsedTitle : item.title,
|
|
235
|
-
isActive:
|
|
253
|
+
isActive: isActive,
|
|
236
254
|
icon: item.icon,
|
|
237
255
|
iconActive: item.iconActive,
|
|
238
256
|
className: classNames(item.className, touchDevice && Styles.pointerEventsNone),
|
|
@@ -265,7 +283,8 @@ LayoutSidebar.displayName = 'LayoutSidebar';
|
|
|
265
283
|
children: /*#__PURE__*/ _jsx(SideNavigationGroupContent, {
|
|
266
284
|
parentId: item.id,
|
|
267
285
|
groups: (_ref1 = (_item_submenu1 = item.submenu) === null || _item_submenu1 === void 0 ? void 0 : _item_submenu1.groups) !== null && _ref1 !== void 0 ? _ref1 : [],
|
|
268
|
-
navigationComponent: navigationComponent
|
|
286
|
+
navigationComponent: navigationComponent,
|
|
287
|
+
onNavigationLinkClick: handleSubmenuLinkClick
|
|
269
288
|
})
|
|
270
289
|
})
|
|
271
290
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/titan-layout/layout-sidebar.tsx"],"sourcesContent":["import { Button, Divider, Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport SvgClose from '@servicetitan/anvil2/assets/icons/material/round/close.svg';\nimport SvgCollapseAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_less.svg';\nimport SvgExpandAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_more.svg';\nimport SvgCollapse from '@servicetitan/anvil2/assets/icons/st/gnav_menu_collapse.svg';\nimport SvgExpand from '@servicetitan/anvil2/assets/icons/st/gnav_menu_expand.svg';\nimport classNames from 'classnames';\nimport { Children, FC, Fragment, ReactElement, isValidElement } from 'react';\nimport { NavigationItemData, NavigationSubmenuData } from '../../utils/navigation';\nimport { NavLinkComponentProps } from '../../utils/navigation-context';\nimport { getModuleNotificationCount } from '../../utils/navigation-notifications';\nimport { getCounterTag, getSubmenuGroupTag } from '../../utils/side-nav';\nimport { PinnedNavigationConfig } from './interface';\nimport { NavigationComponentProps } from './interface-internal';\nimport { LayoutPlacementContext, useTitanLayoutContext } from './layout-context';\nimport {\n InternalSideNavigationGroup,\n InternalSideNavigationGroupLink,\n InternalSideNavigationLink,\n} from './layout-sidebar-links-internal';\nimport * as Styles from './layout-sidebar.module.less';\nimport { NavigationCatalogTrigger } from './navigation-catalog';\nimport { NavigationScrollIndicators } from './navigation-scroll-indicators';\nimport { useNavigationScroll } from './use-navigation-scroll';\nimport { withTooltip } from './with-tooltip';\n\nexport interface LayoutSidebarProps {\n className?: string;\n top?: ReactElement[];\n\n /**\n * Destinations rendered above the divider, ahead of `top`.\n *\n * Separate from `top` rather than widening it: that one takes elements a host builds itself\n * and renders them as-is, which is what a bespoke control needs. This takes navigation items\n * and puts them through the same renderer as `mainItems`, so one with pages beneath it is an\n * expandable group instead of being flattened to a bare link.\n */\n topItems?: NavigationItemData[];\n\n /** Whether the rail shows the scroll and overflow-notification indicators. */\n scrollIndicators?: boolean;\n bottom?: ReactElement;\n mainItems?: NavigationItemData[];\n pinnedNavigation?: PinnedNavigationConfig;\n barExpanded: boolean;\n submenusOpened: string[] | undefined;\n drawerOpened: boolean;\n mobile: boolean;\n touchDevice: boolean;\n navigationComponent: FC<NavLinkComponentProps>;\n onBarExpandChange(expanded: boolean): void;\n onDrawerOpenChange(expanded: boolean): void;\n onSubmenuOpenChange(id: string, opened: boolean): void;\n onSubmenusOpenChange?(ids: string[], opened: boolean): void;\n onNavigationLinkClick?(itemId: string, submenuItemId?: string): void;\n}\n\nexport const LayoutSidebar: FC<LayoutSidebarProps> = ({\n className,\n mobile,\n touchDevice,\n barExpanded,\n submenusOpened,\n drawerOpened,\n onBarExpandChange,\n onSubmenuOpenChange,\n onSubmenusOpenChange,\n onDrawerOpenChange,\n onNavigationLinkClick,\n mainItems,\n pinnedNavigation,\n top,\n topItems,\n scrollIndicators,\n bottom,\n navigationComponent,\n}) => {\n const { regionRef, scrollRef, revealNotification, ...scrollOverflow } =\n useNavigationScroll(scrollIndicators);\n const closeDrawer = () => {\n if (mobile) {\n onDrawerOpenChange?.(false);\n }\n };\n\n const effectiveExpanded = mobile ? drawerOpened : barExpanded;\n /*\n * Both regions, because a destination above the divider expands exactly like one below it.\n * Counting only `mainItems` would let Expand All skip those groups — and hide the control\n * entirely on a rail whose only expandable modules sit up there.\n */\n const expandableIds = [...(topItems ?? []), ...(mainItems ?? [])]\n .filter(item => item.submenu?.groups.some(group => group.links.length > 0))\n .map(item => item.id);\n const hasOpenSubmenus = expandableIds.some(id => submenusOpened?.includes(id));\n const toggleAllLabel = hasOpenSubmenus ? 'Collapse All' : 'Expand All';\n const toggleAll =\n effectiveExpanded && expandableIds.length > 0 && onSubmenusOpenChange\n ? withTooltip(\n <Button\n appearance=\"secondary\"\n size=\"small\"\n icon={hasOpenSubmenus ? SvgCollapseAll : SvgExpandAll}\n aria-label={toggleAllLabel}\n aria-expanded={hasOpenSubmenus}\n data-cy=\"navigation-toggle-all\"\n data-pendo=\"navigation-toggle-all\"\n onClick={event => {\n event.stopPropagation();\n onSubmenusOpenChange(expandableIds, !hasOpenSubmenus);\n }}\n />,\n toggleAllLabel,\n { placement: 'top' }\n )\n : undefined;\n\n const scrollHeader = !mobile && !barExpanded;\n const navigationHeader = (\n <div className={Styles.navHeader}>\n {mobile && (\n <div className={Styles.navCloseWrapper}>\n <div className={Styles.navClose} onClick={() => onBarExpandChange(false)}>\n <Icon svg={SvgClose} size=\"large\" />\n </div>\n </div>\n )}\n {pinnedNavigation && (\n <NavigationCatalogTrigger\n expanded={effectiveExpanded}\n {...pinnedNavigation}\n trailingAction={toggleAll}\n />\n )}\n {!pinnedNavigation && toggleAll && <div className={Styles.navTools}>{toggleAll}</div>}\n </div>\n );\n\n /*\n * Shared by the region above the divider and the list below it, so a destination renders the\n * same way wherever the host puts it. Two copies of this branch would drift.\n */\n const renderItems = (items: NavigationItemData[] | undefined) =>\n items?.map(item =>\n item.submenu ? (\n <SideNavigationGroupItem\n key={item.id}\n item={item}\n barExpanded={effectiveExpanded}\n submenuOpened={!!item.id && !!submenusOpened?.includes(item.id)}\n onSubmenuOpen={onSubmenuOpenChange}\n navigationComponent={navigationComponent}\n onNavigationLinkClick={onNavigationLinkClick}\n touchDevice={touchDevice}\n />\n ) : (\n <InternalSideNavigationLink\n key={item.id}\n id={item.id}\n to={item.to}\n title={effectiveExpanded ? item.title : (item.collapsedTitle ?? item.title)}\n isActive={item.isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={item.className}\n tag={getSubmenuGroupTag(item.submenu, getCounterTag(item.counter, item.tag))}\n navigationComponent={navigationComponent}\n />\n )\n );\n\n return (\n <LayoutPlacementContext.Provider value=\"side\">\n {mobile && drawerOpened && (\n <div className={Styles.navDrawerBackdrop} onClick={closeDrawer} />\n )}\n <div\n className={classNames(\n Styles.nav,\n mobile && Styles.navDrawer,\n mobile && drawerOpened && Styles.navDrawerOpened,\n !mobile && (barExpanded ? Styles.navWide : Styles.navSlim),\n className\n )}\n data-cy=\"side-navigation\"\n onClick={closeDrawer}\n >\n <ThemeProvider mode=\"dark\" className={Styles.navContent}>\n {!scrollHeader && navigationHeader}\n <div ref={regionRef} className={Styles.navScrollRegion}>\n <div ref={scrollRef} className={Styles.navMain} data-cy=\"navigation-scroll\">\n <div>\n {scrollHeader && navigationHeader}\n {(!!top?.length || !!topItems?.length) && (\n <SidebarTop>\n {renderItems(topItems)}\n {top}\n </SidebarTop>\n )}\n\n <div className={Styles.navItems} data-cy=\"navigation-items\">\n {renderItems(mainItems)}\n </div>\n\n {!!bottom && <SidebarBottom>{bottom}</SidebarBottom>}\n </div>\n </div>\n {scrollIndicators && (\n <NavigationScrollIndicators\n {...scrollOverflow}\n expanded={effectiveExpanded}\n onReveal={revealNotification}\n />\n )}\n </div>\n </ThemeProvider>\n\n {!mobile && (\n <ThemeProvider mode=\"dark\" className={Styles.navFooter}>\n <div className={Styles.divider} />\n <div className={Styles.toggleWrapper}>\n <SideNavigationOptionsToggle\n expanded={barExpanded}\n onExpandedChange={() => onBarExpandChange(!barExpanded)}\n />\n </div>\n </ThemeProvider>\n )}\n </div>\n </LayoutPlacementContext.Provider>\n );\n};\nLayoutSidebar.displayName = 'LayoutSidebar';\n\n/** Side Navigation options toggle */\nconst SideNavigationOptionsToggle: FC<{\n expanded: boolean;\n onExpandedChange?(expanded: boolean): void;\n}> = ({ expanded, onExpandedChange }) =>\n withTooltip(\n <Button\n appearance=\"ghost\"\n size=\"small\"\n icon={expanded ? SvgCollapse : SvgExpand}\n data-cy=\"navigation-left-options\"\n data-pendo=\"navigation-left-options\"\n aria-label={expanded ? 'Collapse Menu' : 'Expand Menu'}\n aria-expanded={expanded}\n className={Styles.toggle}\n onClick={() => onExpandedChange?.(!expanded)}\n />,\n expanded ? 'Collapse Menu' : 'Expand Menu',\n { placement: 'right' }\n );\n\n/** Side Navigation menu item */\nconst SideNavigationGroupItem: FC<{\n item: NavigationItemData;\n navigationComponent: FC<NavLinkComponentProps>;\n touchDevice: boolean;\n barExpanded: boolean;\n submenuOpened: boolean;\n onSubmenuOpen: (id: string, opened: boolean) => void;\n onNavigationLinkClick?: (itemId: string, submenuItemId?: string) => void;\n}> = ({\n item,\n onSubmenuOpen,\n onNavigationLinkClick,\n barExpanded,\n submenuOpened,\n navigationComponent,\n touchDevice,\n}) => {\n const {\n sidebar: {\n styles: { popoverContent },\n },\n } = useTitanLayoutContext();\n\n const tag = getSubmenuGroupTag(item.submenu, getCounterTag(item.counter, item.tag));\n\n return barExpanded ? (\n <InternalSideNavigationGroup\n id={item.id}\n to={item.to}\n title={item.title}\n isActive={item.isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={item.className}\n tag={tag}\n notificationCount={getModuleNotificationCount(item, submenuOpened)}\n submenuOpened={submenuOpened}\n onSubmenuOpen={onSubmenuOpen}\n navigationComponent={navigationComponent}\n >\n <SideNavigationGroupContent\n parentId={item.id}\n groups={item.submenu?.groups ?? []}\n navigationComponent={navigationComponent}\n onNavigationLinkClick={onNavigationLinkClick}\n />\n </InternalSideNavigationGroup>\n ) : (\n <Popover\n placement=\"right-start\"\n openOnHover={!touchDevice}\n delay={200}\n noPadding\n disableCaret\n >\n <Popover.Trigger>\n {(triggerProps: any) => (\n <div {...triggerProps}>\n <InternalSideNavigationLink\n id={item.id}\n to={item.to}\n title={item.collapsedTitle ?? item.title}\n isActive={item.isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={classNames(\n item.className,\n touchDevice && Styles.pointerEventsNone\n )}\n tag={tag}\n notificationCount={getModuleNotificationCount(item, false)}\n navigationComponent={navigationComponent}\n />\n </div>\n )}\n </Popover.Trigger>\n <Popover.Content\n style={popoverContent}\n className={classNames('z-global-nav-i', Styles.submenuPopoverContent)}\n data-cy=\"navigation-item-popover-content\"\n >\n <div className={Styles.submenuPopover}>\n <Text\n variant=\"headline\"\n el=\"h4\"\n size=\"small\"\n className={Styles.submenuPopoverTitle}\n >\n {item.title}\n </Text>\n <Divider className={Styles.submenuPopoverDivider} />\n <div className={Styles.submenuPopoverBody}>\n <SideNavigationGroupContent\n parentId={item.id}\n groups={item.submenu?.groups ?? []}\n navigationComponent={navigationComponent}\n />\n </div>\n </div>\n </Popover.Content>\n </Popover>\n );\n};\nconst SideNavigationGroupContent: FC<\n NavigationSubmenuData &\n NavigationComponentProps & {\n parentId: string;\n onNavigationLinkClick?: (itemId: string, submenuItemId?: string) => void;\n }\n> = ({ groups, parentId, navigationComponent, onNavigationLinkClick }) => {\n return (\n <Fragment>\n {groups.map((group, index) => {\n if (!group.links.length) {\n return null;\n }\n\n const title = group.title?.trim() ?? '';\n /* eslint-disable react/no-array-index-key */\n return (\n <div key={`:group:${parentId}:${index}`} className={Styles.submenuGroup}>\n {title && (\n <Text\n variant=\"eyebrow\"\n size=\"small\"\n className={Styles.submenuGroupHeader}\n >\n {title}\n </Text>\n )}\n {group.links.map((link, index) => (\n <InternalSideNavigationGroupLink\n key={`:${parentId}:${link.id}:${index}`}\n id={link.id}\n to={link.to}\n title={link.title}\n isActive={link.isActive}\n className={undefined}\n tag={getCounterTag(link.counter, link.tag)}\n parentId={parentId}\n navigationComponent={navigationComponent}\n onLinkClick={onNavigationLinkClick}\n />\n ))}\n </div>\n );\n /* eslint-enable react/no-array-index-key */\n })}\n </Fragment>\n );\n};\n\nfunction SidebarTop({ children }: any) {\n const list = Children.map(children, child => {\n return child && isValidElement(child) ? child : null;\n });\n return list?.length ? (\n <ThemeProvider mode=\"dark\" className={Styles.navTop} data-cy=\"navigation-items-top\">\n <div className={Styles.navTopItems}>{list}</div>\n {/* Anvil 2 spacing 3 resolves to the design's 12px above and below. */}\n <Divider spacing={3} className={Styles.topDivider} />\n </ThemeProvider>\n ) : null;\n}\n\nfunction SidebarBottom({ children }: any) {\n return (\n <ThemeProvider mode=\"dark\" className={Styles.navBottom} data-cy=\"navigation-items-bottom\">\n <div className={Styles.divider} />\n {children}\n </ThemeProvider>\n );\n}\n"],"names":["Button","Divider","Icon","Popover","Text","ThemeProvider","SvgClose","SvgCollapseAll","SvgExpandAll","SvgCollapse","SvgExpand","classNames","Children","Fragment","isValidElement","getModuleNotificationCount","getCounterTag","getSubmenuGroupTag","LayoutPlacementContext","useTitanLayoutContext","InternalSideNavigationGroup","InternalSideNavigationGroupLink","InternalSideNavigationLink","Styles","NavigationCatalogTrigger","NavigationScrollIndicators","useNavigationScroll","withTooltip","LayoutSidebar","className","mobile","touchDevice","barExpanded","submenusOpened","drawerOpened","onBarExpandChange","onSubmenuOpenChange","onSubmenusOpenChange","onDrawerOpenChange","onNavigationLinkClick","mainItems","pinnedNavigation","top","topItems","scrollIndicators","bottom","navigationComponent","regionRef","scrollRef","revealNotification","scrollOverflow","closeDrawer","effectiveExpanded","expandableIds","filter","item","submenu","groups","some","group","links","length","map","id","hasOpenSubmenus","includes","toggleAllLabel","toggleAll","appearance","size","icon","aria-label","aria-expanded","data-cy","data-pendo","onClick","event","stopPropagation","placement","undefined","scrollHeader","navigationHeader","div","navHeader","navCloseWrapper","navClose","svg","expanded","trailingAction","navTools","renderItems","items","SideNavigationGroupItem","submenuOpened","onSubmenuOpen","to","title","collapsedTitle","isActive","iconActive","tag","counter","Provider","value","navDrawerBackdrop","nav","navDrawer","navDrawerOpened","navWide","navSlim","mode","navContent","ref","navScrollRegion","navMain","SidebarTop","navItems","SidebarBottom","onReveal","navFooter","divider","toggleWrapper","SideNavigationOptionsToggle","onExpandedChange","displayName","toggle","sidebar","styles","popoverContent","notificationCount","SideNavigationGroupContent","parentId","openOnHover","delay","noPadding","disableCaret","Trigger","triggerProps","pointerEventsNone","Content","style","submenuPopoverContent","submenuPopover","variant","el","submenuPopoverTitle","submenuPopoverDivider","submenuPopoverBody","index","trim","submenuGroup","submenuGroupHeader","link","onLinkClick","children","list","child","navTop","navTopItems","spacing","topDivider","navBottom"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/titan-layout/layout-sidebar.tsx"],"sourcesContent":["import { Button, Divider, Flex, Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport SvgClose from '@servicetitan/anvil2/assets/icons/material/round/close.svg';\nimport SvgCollapseAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_less.svg';\nimport SvgExpandAll from '@servicetitan/anvil2/assets/icons/material/round/unfold_more.svg';\nimport SvgCollapse from '@servicetitan/anvil2/assets/icons/st/gnav_menu_collapse.svg';\nimport SvgExpand from '@servicetitan/anvil2/assets/icons/st/gnav_menu_expand.svg';\nimport classNames from 'classnames';\nimport { Children, FC, Fragment, ReactElement, isValidElement, useCallback, useRef } from 'react';\nimport { NavigationItemData, NavigationSubmenuData } from '../../utils/navigation';\nimport { NavLinkComponentProps } from '../../utils/navigation-context';\nimport { getModuleNotificationCount } from '../../utils/navigation-notifications';\nimport {\n getCounterTag,\n getModuleActiveMatcher,\n getModuleDestination,\n getSubmenuGroupTag,\n} from '../../utils/side-nav';\nimport { PinnedNavigationConfig } from './interface';\nimport { NavigationComponentProps } from './interface-internal';\nimport { LayoutPlacementContext, useTitanLayoutContext } from './layout-context';\nimport {\n InternalSideNavigationGroup,\n InternalSideNavigationGroupLink,\n InternalSideNavigationLink,\n} from './layout-sidebar-links-internal';\nimport * as Styles from './layout-sidebar.module.less';\nimport { NavigationCatalogTrigger } from './navigation-catalog';\nimport { NavigationScrollIndicators } from './navigation-scroll-indicators';\nimport { useNavigationScroll } from './use-navigation-scroll';\nimport { withTooltip } from './with-tooltip';\n\nexport interface LayoutSidebarProps {\n className?: string;\n top?: ReactElement[];\n\n /**\n * Destinations rendered above the divider, ahead of `top`.\n *\n * Separate from `top` rather than widening it: that one takes elements a host builds itself\n * and renders them as-is, which is what a bespoke control needs. This takes navigation items\n * and puts them through the same renderer as `mainItems`, so one with pages beneath it is an\n * expandable group instead of being flattened to a bare link.\n */\n topItems?: NavigationItemData[];\n\n /** Whether the rail shows the scroll and overflow-notification indicators. */\n scrollIndicators?: boolean;\n bottom?: ReactElement;\n mainItems?: NavigationItemData[];\n pinnedNavigation?: PinnedNavigationConfig;\n barExpanded: boolean;\n submenusOpened: string[] | undefined;\n drawerOpened: boolean;\n mobile: boolean;\n touchDevice: boolean;\n navigationComponent: FC<NavLinkComponentProps>;\n onBarExpandChange(expanded: boolean): void;\n onDrawerOpenChange(expanded: boolean): void;\n onSubmenuOpenChange(id: string, opened: boolean): void;\n onSubmenusOpenChange?(ids: string[], opened: boolean): void;\n onNavigationLinkClick?(itemId: string, submenuItemId?: string): void;\n}\n\nexport const LayoutSidebar: FC<LayoutSidebarProps> = ({\n className,\n mobile,\n touchDevice,\n barExpanded,\n submenusOpened,\n drawerOpened,\n onBarExpandChange,\n onSubmenuOpenChange,\n onSubmenusOpenChange,\n onDrawerOpenChange,\n onNavigationLinkClick,\n mainItems,\n pinnedNavigation,\n top,\n topItems,\n scrollIndicators,\n bottom,\n navigationComponent,\n}) => {\n const { regionRef, scrollRef, revealNotification, ...scrollOverflow } =\n useNavigationScroll(scrollIndicators);\n const closeDrawer = () => {\n if (mobile) {\n onDrawerOpenChange?.(false);\n }\n };\n\n const effectiveExpanded = mobile ? drawerOpened : barExpanded;\n /*\n * Both regions, because a destination above the divider expands exactly like one below it.\n * Counting only `mainItems` would let Expand All skip those groups — and hide the control\n * entirely on a rail whose only expandable modules sit up there.\n */\n const expandableIds = [...(topItems ?? []), ...(mainItems ?? [])]\n .filter(item => item.submenu?.groups.some(group => group.links.length > 0))\n .map(item => item.id);\n const hasOpenSubmenus = expandableIds.some(id => submenusOpened?.includes(id));\n const toggleAllLabel = hasOpenSubmenus ? 'Collapse All' : 'Expand All';\n const toggleAll =\n effectiveExpanded && expandableIds.length > 0 && onSubmenusOpenChange\n ? withTooltip(\n <Button\n appearance=\"secondary\"\n size=\"small\"\n icon={hasOpenSubmenus ? SvgCollapseAll : SvgExpandAll}\n aria-label={toggleAllLabel}\n aria-expanded={hasOpenSubmenus}\n data-cy=\"navigation-toggle-all\"\n data-pendo=\"navigation-toggle-all\"\n onClick={event => {\n event.stopPropagation();\n onSubmenusOpenChange(expandableIds, !hasOpenSubmenus);\n }}\n />,\n toggleAllLabel,\n { placement: 'top' }\n )\n : undefined;\n\n const scrollHeader = !mobile && !barExpanded;\n const navigationHeader = (\n <div className={Styles.navHeader}>\n {mobile && (\n <div className={Styles.navCloseWrapper}>\n <div className={Styles.navClose} onClick={() => onBarExpandChange(false)}>\n <Icon svg={SvgClose} size=\"large\" />\n </div>\n </div>\n )}\n {pinnedNavigation && (\n <NavigationCatalogTrigger\n expanded={effectiveExpanded}\n {...pinnedNavigation}\n trailingAction={toggleAll}\n />\n )}\n {!pinnedNavigation && toggleAll && <div className={Styles.navTools}>{toggleAll}</div>}\n </div>\n );\n\n /*\n * Shared by the region above the divider and the list below it, so a destination renders the\n * same way wherever the host puts it. Two copies of this branch would drift.\n */\n const renderItems = (items: NavigationItemData[] | undefined) =>\n items?.map(item =>\n item.submenu ? (\n <SideNavigationGroupItem\n key={item.id}\n item={item}\n barExpanded={effectiveExpanded}\n submenuOpened={!!item.id && !!submenusOpened?.includes(item.id)}\n onSubmenuOpen={onSubmenuOpenChange}\n navigationComponent={navigationComponent}\n onNavigationLinkClick={onNavigationLinkClick}\n touchDevice={touchDevice}\n />\n ) : (\n <InternalSideNavigationLink\n key={item.id}\n id={item.id}\n to={item.to}\n title={effectiveExpanded ? item.title : (item.collapsedTitle ?? item.title)}\n isActive={item.isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={item.className}\n tag={getSubmenuGroupTag(item.submenu, getCounterTag(item.counter, item.tag))}\n navigationComponent={navigationComponent}\n />\n )\n );\n\n return (\n <LayoutPlacementContext.Provider value=\"side\">\n {mobile && drawerOpened && (\n <div className={Styles.navDrawerBackdrop} onClick={closeDrawer} />\n )}\n <div\n className={classNames(\n Styles.nav,\n mobile && Styles.navDrawer,\n mobile && drawerOpened && Styles.navDrawerOpened,\n !mobile && (barExpanded ? Styles.navWide : Styles.navSlim),\n className\n )}\n data-cy=\"side-navigation\"\n onClick={closeDrawer}\n >\n <ThemeProvider mode=\"dark\" className={Styles.navContent}>\n {!scrollHeader && navigationHeader}\n <div ref={regionRef} className={Styles.navScrollRegion}>\n <div ref={scrollRef} className={Styles.navMain} data-cy=\"navigation-scroll\">\n <div>\n {scrollHeader && navigationHeader}\n {(!!top?.length || !!topItems?.length) && (\n <SidebarTop>\n {renderItems(topItems)}\n {top}\n </SidebarTop>\n )}\n\n <div className={Styles.navItems} data-cy=\"navigation-items\">\n {renderItems(mainItems)}\n </div>\n\n {!!bottom && <SidebarBottom>{bottom}</SidebarBottom>}\n </div>\n </div>\n {scrollIndicators && (\n <NavigationScrollIndicators\n {...scrollOverflow}\n expanded={effectiveExpanded}\n onReveal={revealNotification}\n />\n )}\n </div>\n </ThemeProvider>\n\n {!mobile && (\n <ThemeProvider mode=\"dark\" className={Styles.navFooter}>\n <div className={Styles.divider} />\n <Flex direction=\"column\" className={Styles.toggleWrapper}>\n <SideNavigationOptionsToggle\n expanded={barExpanded}\n onExpandedChange={() => onBarExpandChange(!barExpanded)}\n />\n </Flex>\n </ThemeProvider>\n )}\n </div>\n </LayoutPlacementContext.Provider>\n );\n};\nLayoutSidebar.displayName = 'LayoutSidebar';\n\n/** Side Navigation options toggle */\nconst SideNavigationOptionsToggle: FC<{\n expanded: boolean;\n onExpandedChange?(expanded: boolean): void;\n}> = ({ expanded, onExpandedChange }) =>\n withTooltip(\n <Button\n appearance=\"ghost\"\n size=\"small\"\n flexGrow={1}\n justifyContent=\"flex-start\"\n icon={expanded ? SvgCollapse : SvgExpand}\n data-cy=\"navigation-left-options\"\n data-pendo=\"navigation-left-options\"\n aria-label={expanded ? 'Collapse Menu' : 'Expand Menu'}\n aria-expanded={expanded}\n className={Styles.toggle}\n onClick={() => onExpandedChange?.(!expanded)}\n />,\n expanded ? 'Collapse Menu' : 'Expand Menu',\n { placement: 'right', pointerEventsNone: true }\n );\n\n/** Side Navigation menu item */\nconst SideNavigationGroupItem: FC<{\n item: NavigationItemData;\n navigationComponent: FC<NavLinkComponentProps>;\n touchDevice: boolean;\n barExpanded: boolean;\n submenuOpened: boolean;\n onSubmenuOpen: (id: string, opened: boolean) => void;\n onNavigationLinkClick?: (itemId: string, submenuItemId?: string) => void;\n}> = ({\n item,\n onSubmenuOpen,\n onNavigationLinkClick,\n barExpanded,\n submenuOpened,\n navigationComponent,\n touchDevice,\n}) => {\n const {\n sidebar: {\n styles: { popoverContent },\n },\n } = useTitanLayoutContext();\n\n const tag = getSubmenuGroupTag(item.submenu, getCounterTag(item.counter, item.tag));\n const isActive = item.isActive ?? getModuleActiveMatcher(item.to, item.submenu);\n\n /*\n * Some destinations (legacy monolith pages) never fire the route-change signal the popover\n * would otherwise rely on to dismiss itself, leaving it stranded open over the loaded page.\n * Closing explicitly on click, rather than waiting on navigation to settle, works everywhere.\n */\n const popoverRef = useRef<{ closePopover: () => void }>(null);\n const handleSubmenuLinkClick = useCallback(\n (itemId: string, submenuItemId?: string) => {\n popoverRef.current?.closePopover();\n onNavigationLinkClick?.(itemId, submenuItemId);\n },\n [onNavigationLinkClick]\n );\n\n return barExpanded ? (\n <InternalSideNavigationGroup\n id={item.id}\n to={getModuleDestination(item.to, item.submenu)}\n title={item.title}\n isActive={isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={item.className}\n tag={tag}\n notificationCount={getModuleNotificationCount(item, submenuOpened)}\n submenuOpened={submenuOpened}\n onSubmenuOpen={onSubmenuOpen}\n navigationComponent={navigationComponent}\n >\n <SideNavigationGroupContent\n parentId={item.id}\n groups={item.submenu?.groups ?? []}\n navigationComponent={navigationComponent}\n onNavigationLinkClick={onNavigationLinkClick}\n />\n </InternalSideNavigationGroup>\n ) : (\n <Popover\n ref={popoverRef}\n placement=\"right-start\"\n openOnHover={!touchDevice}\n delay={200}\n noPadding\n disableCaret\n >\n <Popover.Trigger>\n {(triggerProps: any) => (\n <div {...triggerProps}>\n <InternalSideNavigationLink\n id={item.id}\n to={getModuleDestination(item.to, item.submenu)}\n title={item.collapsedTitle ?? item.title}\n isActive={isActive}\n icon={item.icon}\n iconActive={item.iconActive}\n className={classNames(\n item.className,\n touchDevice && Styles.pointerEventsNone\n )}\n tag={tag}\n notificationCount={getModuleNotificationCount(item, false)}\n navigationComponent={navigationComponent}\n />\n </div>\n )}\n </Popover.Trigger>\n <Popover.Content\n style={popoverContent}\n className={classNames('z-global-nav-i', Styles.submenuPopoverContent)}\n data-cy=\"navigation-item-popover-content\"\n >\n <div className={Styles.submenuPopover}>\n <Text\n variant=\"headline\"\n el=\"h4\"\n size=\"small\"\n className={Styles.submenuPopoverTitle}\n >\n {item.title}\n </Text>\n <Divider className={Styles.submenuPopoverDivider} />\n <div className={Styles.submenuPopoverBody}>\n <SideNavigationGroupContent\n parentId={item.id}\n groups={item.submenu?.groups ?? []}\n navigationComponent={navigationComponent}\n onNavigationLinkClick={handleSubmenuLinkClick}\n />\n </div>\n </div>\n </Popover.Content>\n </Popover>\n );\n};\nconst SideNavigationGroupContent: FC<\n NavigationSubmenuData &\n NavigationComponentProps & {\n parentId: string;\n onNavigationLinkClick?: (itemId: string, submenuItemId?: string) => void;\n }\n> = ({ groups, parentId, navigationComponent, onNavigationLinkClick }) => {\n return (\n <Fragment>\n {groups.map((group, index) => {\n if (!group.links.length) {\n return null;\n }\n\n const title = group.title?.trim() ?? '';\n /* eslint-disable react/no-array-index-key */\n return (\n <div key={`:group:${parentId}:${index}`} className={Styles.submenuGroup}>\n {title && (\n <Text\n variant=\"eyebrow\"\n size=\"small\"\n className={Styles.submenuGroupHeader}\n >\n {title}\n </Text>\n )}\n {group.links.map((link, index) => (\n <InternalSideNavigationGroupLink\n key={`:${parentId}:${link.id}:${index}`}\n id={link.id}\n to={link.to}\n title={link.title}\n isActive={link.isActive}\n className={undefined}\n tag={getCounterTag(link.counter, link.tag)}\n parentId={parentId}\n navigationComponent={navigationComponent}\n onLinkClick={onNavigationLinkClick}\n />\n ))}\n </div>\n );\n /* eslint-enable react/no-array-index-key */\n })}\n </Fragment>\n );\n};\n\nfunction SidebarTop({ children }: any) {\n const list = Children.map(children, child => {\n return child && isValidElement(child) ? child : null;\n });\n return list?.length ? (\n <ThemeProvider mode=\"dark\" className={Styles.navTop} data-cy=\"navigation-items-top\">\n <div className={Styles.navTopItems}>{list}</div>\n {/* Anvil 2 spacing 3 resolves to the design's 12px above and below. */}\n <Divider spacing={3} className={Styles.topDivider} />\n </ThemeProvider>\n ) : null;\n}\n\nfunction SidebarBottom({ children }: any) {\n return (\n <ThemeProvider mode=\"dark\" className={Styles.navBottom} data-cy=\"navigation-items-bottom\">\n <div className={Styles.divider} />\n {children}\n </ThemeProvider>\n );\n}\n"],"names":["Button","Divider","Flex","Icon","Popover","Text","ThemeProvider","SvgClose","SvgCollapseAll","SvgExpandAll","SvgCollapse","SvgExpand","classNames","Children","Fragment","isValidElement","useCallback","useRef","getModuleNotificationCount","getCounterTag","getModuleActiveMatcher","getModuleDestination","getSubmenuGroupTag","LayoutPlacementContext","useTitanLayoutContext","InternalSideNavigationGroup","InternalSideNavigationGroupLink","InternalSideNavigationLink","Styles","NavigationCatalogTrigger","NavigationScrollIndicators","useNavigationScroll","withTooltip","LayoutSidebar","className","mobile","touchDevice","barExpanded","submenusOpened","drawerOpened","onBarExpandChange","onSubmenuOpenChange","onSubmenusOpenChange","onDrawerOpenChange","onNavigationLinkClick","mainItems","pinnedNavigation","top","topItems","scrollIndicators","bottom","navigationComponent","regionRef","scrollRef","revealNotification","scrollOverflow","closeDrawer","effectiveExpanded","expandableIds","filter","item","submenu","groups","some","group","links","length","map","id","hasOpenSubmenus","includes","toggleAllLabel","toggleAll","appearance","size","icon","aria-label","aria-expanded","data-cy","data-pendo","onClick","event","stopPropagation","placement","undefined","scrollHeader","navigationHeader","div","navHeader","navCloseWrapper","navClose","svg","expanded","trailingAction","navTools","renderItems","items","SideNavigationGroupItem","submenuOpened","onSubmenuOpen","to","title","collapsedTitle","isActive","iconActive","tag","counter","Provider","value","navDrawerBackdrop","nav","navDrawer","navDrawerOpened","navWide","navSlim","mode","navContent","ref","navScrollRegion","navMain","SidebarTop","navItems","SidebarBottom","onReveal","navFooter","divider","direction","toggleWrapper","SideNavigationOptionsToggle","onExpandedChange","displayName","flexGrow","justifyContent","toggle","pointerEventsNone","sidebar","styles","popoverContent","popoverRef","handleSubmenuLinkClick","itemId","submenuItemId","current","closePopover","notificationCount","SideNavigationGroupContent","parentId","openOnHover","delay","noPadding","disableCaret","Trigger","triggerProps","Content","style","submenuPopoverContent","submenuPopover","variant","el","submenuPopoverTitle","submenuPopoverDivider","submenuPopoverBody","index","trim","submenuGroup","submenuGroupHeader","link","onLinkClick","children","list","child","navTop","navTopItems","spacing","topDivider","navBottom"],"mappings":"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"}
|
|
@@ -401,7 +401,6 @@
|
|
|
401
401
|
background-color: @bg-color;
|
|
402
402
|
|
|
403
403
|
.toggle-wrapper {
|
|
404
|
-
display: flex;
|
|
405
404
|
padding: @spacing-1 @spacing-1 @spacing-1 14px;
|
|
406
405
|
}
|
|
407
406
|
|
|
@@ -620,6 +619,7 @@
|
|
|
620
619
|
|
|
621
620
|
.submenu-popover-title[data-anv][data-anv] {
|
|
622
621
|
color: @color-white;
|
|
622
|
+
font-size: @typescale-2;
|
|
623
623
|
margin-bottom: @spacing-0;
|
|
624
624
|
margin-top: @spacing-1;
|
|
625
625
|
padding: @spacing-1;
|
|
@@ -69,7 +69,7 @@ import * as styles from './navigation-catalog-trigger.module.less';
|
|
|
69
69
|
* that opens a dialog rather than a destination, so sharing the namespace invites a
|
|
70
70
|
* selector written for a link to match it.
|
|
71
71
|
*/ 'data-cy': 'navigation-catalog-trigger',
|
|
72
|
-
'data-pendo': '
|
|
72
|
+
'data-pendo': 'global-nav-go-to',
|
|
73
73
|
'appearance': 'secondary',
|
|
74
74
|
'size': 'small',
|
|
75
75
|
'aria-label': 'Go to',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.tsx"],"sourcesContent":["import { Button, Chip, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport IconSearch from '@servicetitan/anvil2/assets/icons/material/round/search.svg';\nimport classNames from 'classnames';\nimport { FC, Fragment, ReactNode, useCallback, useEffect, useRef, useState } from 'react';\nimport { PinnedNavigationConfig } from '../interface';\nimport { NavigationCatalog } from './navigation-catalog';\n\nimport * as styles from './navigation-catalog-trigger.module.less';\n\n/**\n * True when the keystroke should open the catalog rather than reach the focused control.\n *\n * The shortcut is deliberately a modifier chord: a bare key would be swallowed by, or would steal\n * from, every text field on the page.\n */\nconst isCatalogShortcut = (event: KeyboardEvent): boolean =>\n (event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === 'k';\n\n/**\n * The chord as the user's own keyboard prints it.\n *\n * The listener accepts either modifier on every platform, so this only decides which one to\n * advertise. `platform` is deprecated but is still the only reliable signal here; the user agent is\n * the fallback and a wrong guess costs nothing but a mislabelled badge.\n */\nconst shortcutLabel = (): string => {\n const platform =\n typeof window.navigator === 'undefined'\n ? ''\n : window.navigator.platform || window.navigator.userAgent;\n\n return /Mac|iPod|iPhone|iPad/.test(platform) ? '⌘ K' : 'Ctrl K';\n};\n\nexport interface NavigationCatalogTriggerProps extends PinnedNavigationConfig {\n /** Whether the rail is expanded; the compact trigger keeps its label below the icon. */\n expanded: boolean;\n /** Optional sidebar action beside the expanded search trigger. */\n trailingAction?: ReactNode;\n}\n\n/**\n * Sidebar entry point for the navigation catalog.\n *\n * Presented as a labelled control rather than a bare icon: the catalog is the only route to an\n * unpinned destination, so the affordance has to read as \"search everything\" at a glance. It is a\n * button and not an input — the real field lives in the dialog and takes focus on open, and two\n * inputs would mean typing in one and getting results in the other.\n *\n * The catalog is never opened automatically; an unpinned navigation is a deliberate state, and this\n * trigger plus its shortcut are what keep the user from being stranded there.\n */\nexport const NavigationCatalogTrigger: FC<NavigationCatalogTriggerProps> = ({\n expanded,\n trailingAction,\n ...catalog\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const wasOpen = useRef(false);\n\n const close = useCallback(() => setIsOpen(false), []);\n const toggle = useCallback(() => setIsOpen(open => !open), []);\n\n useEffect(() => {\n // The dialog unmounts on close, so restore focus after its modal content is removed.\n if (wasOpen.current && !isOpen) {\n triggerRef.current?.focus();\n }\n wasOpen.current = isOpen;\n }, [isOpen]);\n\n useEffect(() => {\n const handler = (event: KeyboardEvent) => {\n if (!isCatalogShortcut(event)) {\n return;\n }\n\n event.preventDefault();\n toggle();\n };\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [toggle]);\n\n /*\n * Labelled explicitly so the name stays \"Go to\" whether or not the text is rendered, and so the\n * shortcut badge never reads out as part of it.\n */\n const buttonProps = {\n /*\n * Not `navigation-item-*`: that prefix belongs to the rail's links, and this is a control\n * that opens a dialog rather than a destination, so sharing the namespace invites a\n * selector written for a link to match it.\n */\n 'data-cy': 'navigation-catalog-trigger',\n 'data-pendo': 'navigation-catalog-trigger',\n 'appearance': 'secondary',\n 'size': 'small',\n 'aria-label': 'Go to',\n 'aria-haspopup': 'dialog',\n 'aria-expanded': isOpen,\n 'aria-keyshortcuts': 'Meta+K Control+K',\n 'onClick': toggle,\n } as const;\n\n return (\n <Fragment>\n <div className={classNames(styles.container, !expanded && styles.containerCollapsed)}>\n {expanded ? (\n <Button\n {...buttonProps}\n ref={triggerRef}\n icon={{ before: IconSearch }}\n className={styles.trigger}\n >\n <Flex alignItems=\"center\" justifyContent=\"space-between\" gap={1} grow={1}>\n {/* The ellipsis is part of the label, matching the field in the dialog. */}\n <Text inline size=\"small\" className={styles.triggerLabel}>\n Go to...\n </Text>\n {/* Decorative: the chord is already on the button as aria-keyshortcuts. */}\n <Chip\n label={shortcutLabel()}\n size=\"small\"\n className={styles.shortcut}\n />\n </Flex>\n </Button>\n ) : (\n <Button\n {...buttonProps}\n ref={triggerRef}\n appearance=\"ghost\"\n icon={IconSearch}\n className={styles.triggerCollapsed}\n >\n <span className={styles.collapsedLabel}>Go to...</span>\n </Button>\n )}\n {expanded && trailingAction}\n </div>\n {/*\n * Mounted only while open, so a host that resolves its catalog lazily is not asked for\n * it on every page load, and a second navigation tree is not held inside the sidebar's\n * subtree for a dialog nobody opened.\n *\n * Dark, because the catalog belongs to the rail rather than to the page. The rail paints\n * itself dark whatever the application's mode is, and this is the rail's own menu — the\n * same `ThemeProvider` the rail uses on its own sections.\n *\n * A `ThemeProvider` rather than a second `AnvilProvider`: the latter is the\n * application-level provider, and mounting a nested one alongside the host's meant its\n * unmount tore down state the outer one was still relying on, so closing the catalog\n * left the rail unstyled.\n *\n * This only sets the mode, which is what makes the *text* tokens light. The surface is\n * matched to the rail separately, in `navigation-catalog.module.less` — anvil2's dark is\n * a neutral grey and the rail's is a navy, so the mode alone would leave two visibly\n * different darks.\n */}\n {isOpen && (\n <ThemeProvider mode=\"dark\">\n <NavigationCatalog open onClose={close} {...catalog} />\n </ThemeProvider>\n )}\n </Fragment>\n );\n};\n"],"names":["Button","Chip","Flex","Text","ThemeProvider","IconSearch","classNames","Fragment","useCallback","useEffect","useRef","useState","NavigationCatalog","styles","isCatalogShortcut","event","metaKey","ctrlKey","altKey","key","toLowerCase","shortcutLabel","platform","window","navigator","userAgent","test","NavigationCatalogTrigger","expanded","trailingAction","catalog","isOpen","setIsOpen","triggerRef","wasOpen","close","toggle","open","current","focus","handler","preventDefault","addEventListener","removeEventListener","buttonProps","div","className","container","containerCollapsed","ref","icon","before","trigger","alignItems","justifyContent","gap","grow","inline","size","triggerLabel","label","shortcut","appearance","triggerCollapsed","span","collapsedLabel","mode","onClose"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.tsx"],"sourcesContent":["import { Button, Chip, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport IconSearch from '@servicetitan/anvil2/assets/icons/material/round/search.svg';\nimport classNames from 'classnames';\nimport { FC, Fragment, ReactNode, useCallback, useEffect, useRef, useState } from 'react';\nimport { PinnedNavigationConfig } from '../interface';\nimport { NavigationCatalog } from './navigation-catalog';\n\nimport * as styles from './navigation-catalog-trigger.module.less';\n\n/**\n * True when the keystroke should open the catalog rather than reach the focused control.\n *\n * The shortcut is deliberately a modifier chord: a bare key would be swallowed by, or would steal\n * from, every text field on the page.\n */\nconst isCatalogShortcut = (event: KeyboardEvent): boolean =>\n (event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === 'k';\n\n/**\n * The chord as the user's own keyboard prints it.\n *\n * The listener accepts either modifier on every platform, so this only decides which one to\n * advertise. `platform` is deprecated but is still the only reliable signal here; the user agent is\n * the fallback and a wrong guess costs nothing but a mislabelled badge.\n */\nconst shortcutLabel = (): string => {\n const platform =\n typeof window.navigator === 'undefined'\n ? ''\n : window.navigator.platform || window.navigator.userAgent;\n\n return /Mac|iPod|iPhone|iPad/.test(platform) ? '⌘ K' : 'Ctrl K';\n};\n\nexport interface NavigationCatalogTriggerProps extends PinnedNavigationConfig {\n /** Whether the rail is expanded; the compact trigger keeps its label below the icon. */\n expanded: boolean;\n /** Optional sidebar action beside the expanded search trigger. */\n trailingAction?: ReactNode;\n}\n\n/**\n * Sidebar entry point for the navigation catalog.\n *\n * Presented as a labelled control rather than a bare icon: the catalog is the only route to an\n * unpinned destination, so the affordance has to read as \"search everything\" at a glance. It is a\n * button and not an input — the real field lives in the dialog and takes focus on open, and two\n * inputs would mean typing in one and getting results in the other.\n *\n * The catalog is never opened automatically; an unpinned navigation is a deliberate state, and this\n * trigger plus its shortcut are what keep the user from being stranded there.\n */\nexport const NavigationCatalogTrigger: FC<NavigationCatalogTriggerProps> = ({\n expanded,\n trailingAction,\n ...catalog\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const wasOpen = useRef(false);\n\n const close = useCallback(() => setIsOpen(false), []);\n const toggle = useCallback(() => setIsOpen(open => !open), []);\n\n useEffect(() => {\n // The dialog unmounts on close, so restore focus after its modal content is removed.\n if (wasOpen.current && !isOpen) {\n triggerRef.current?.focus();\n }\n wasOpen.current = isOpen;\n }, [isOpen]);\n\n useEffect(() => {\n const handler = (event: KeyboardEvent) => {\n if (!isCatalogShortcut(event)) {\n return;\n }\n\n event.preventDefault();\n toggle();\n };\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [toggle]);\n\n /*\n * Labelled explicitly so the name stays \"Go to\" whether or not the text is rendered, and so the\n * shortcut badge never reads out as part of it.\n */\n const buttonProps = {\n /*\n * Not `navigation-item-*`: that prefix belongs to the rail's links, and this is a control\n * that opens a dialog rather than a destination, so sharing the namespace invites a\n * selector written for a link to match it.\n */\n 'data-cy': 'navigation-catalog-trigger',\n 'data-pendo': 'global-nav-go-to',\n 'appearance': 'secondary',\n 'size': 'small',\n 'aria-label': 'Go to',\n 'aria-haspopup': 'dialog',\n 'aria-expanded': isOpen,\n 'aria-keyshortcuts': 'Meta+K Control+K',\n 'onClick': toggle,\n } as const;\n\n return (\n <Fragment>\n <div className={classNames(styles.container, !expanded && styles.containerCollapsed)}>\n {expanded ? (\n <Button\n {...buttonProps}\n ref={triggerRef}\n icon={{ before: IconSearch }}\n className={styles.trigger}\n >\n <Flex alignItems=\"center\" justifyContent=\"space-between\" gap={1} grow={1}>\n {/* The ellipsis is part of the label, matching the field in the dialog. */}\n <Text inline size=\"small\" className={styles.triggerLabel}>\n Go to...\n </Text>\n {/* Decorative: the chord is already on the button as aria-keyshortcuts. */}\n <Chip\n label={shortcutLabel()}\n size=\"small\"\n className={styles.shortcut}\n />\n </Flex>\n </Button>\n ) : (\n <Button\n {...buttonProps}\n ref={triggerRef}\n appearance=\"ghost\"\n icon={IconSearch}\n className={styles.triggerCollapsed}\n >\n <span className={styles.collapsedLabel}>Go to...</span>\n </Button>\n )}\n {expanded && trailingAction}\n </div>\n {/*\n * Mounted only while open, so a host that resolves its catalog lazily is not asked for\n * it on every page load, and a second navigation tree is not held inside the sidebar's\n * subtree for a dialog nobody opened.\n *\n * Dark, because the catalog belongs to the rail rather than to the page. The rail paints\n * itself dark whatever the application's mode is, and this is the rail's own menu — the\n * same `ThemeProvider` the rail uses on its own sections.\n *\n * A `ThemeProvider` rather than a second `AnvilProvider`: the latter is the\n * application-level provider, and mounting a nested one alongside the host's meant its\n * unmount tore down state the outer one was still relying on, so closing the catalog\n * left the rail unstyled.\n *\n * This only sets the mode, which is what makes the *text* tokens light. The surface is\n * matched to the rail separately, in `navigation-catalog.module.less` — anvil2's dark is\n * a neutral grey and the rail's is a navy, so the mode alone would leave two visibly\n * different darks.\n */}\n {isOpen && (\n <ThemeProvider mode=\"dark\">\n <NavigationCatalog open onClose={close} {...catalog} />\n </ThemeProvider>\n )}\n </Fragment>\n );\n};\n"],"names":["Button","Chip","Flex","Text","ThemeProvider","IconSearch","classNames","Fragment","useCallback","useEffect","useRef","useState","NavigationCatalog","styles","isCatalogShortcut","event","metaKey","ctrlKey","altKey","key","toLowerCase","shortcutLabel","platform","window","navigator","userAgent","test","NavigationCatalogTrigger","expanded","trailingAction","catalog","isOpen","setIsOpen","triggerRef","wasOpen","close","toggle","open","current","focus","handler","preventDefault","addEventListener","removeEventListener","buttonProps","div","className","container","containerCollapsed","ref","icon","before","trigger","alignItems","justifyContent","gap","grow","inline","size","triggerLabel","label","shortcut","appearance","triggerCollapsed","span","collapsedLabel","mode","onClose"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-catalog.d.ts","sourceRoot":"","sources":["../../../../src/components/titan-layout/navigation-catalog/navigation-catalog.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,EAAE,EAAmD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"navigation-catalog.d.ts","sourceRoot":"","sources":["../../../../src/components/titan-layout/navigation-catalog/navigation-catalog.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,EAAE,EAAmD,MAAM,OAAO,CAAC;AAS5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAmMtD,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB;IAClE,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkNxD,CAAC"}
|