@primer/react 0.0.0-20260619134534 → 0.0.0-20260619191426

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +5 -3
  2. package/dist/ConfirmationDialog/useConfirm.d.ts.map +1 -1
  3. package/dist/ConfirmationDialog/useConfirm.js +8 -4
  4. package/dist/UnderlineNav/UnderlineNav-263b4e8f.css +2 -0
  5. package/dist/UnderlineNav/UnderlineNav-263b4e8f.css.map +1 -0
  6. package/dist/UnderlineNav/UnderlineNav.d.ts +1 -2
  7. package/dist/UnderlineNav/UnderlineNav.d.ts.map +1 -1
  8. package/dist/UnderlineNav/UnderlineNav.js +86 -332
  9. package/dist/UnderlineNav/UnderlineNav.module.css.js +2 -2
  10. package/dist/UnderlineNav/UnderlineNavContext.d.ts +1 -11
  11. package/dist/UnderlineNav/UnderlineNavContext.d.ts.map +1 -1
  12. package/dist/UnderlineNav/UnderlineNavContext.js +1 -4
  13. package/dist/UnderlineNav/UnderlineNavItem-402cd41c.css +2 -0
  14. package/dist/UnderlineNav/UnderlineNavItem-402cd41c.css.map +1 -0
  15. package/dist/UnderlineNav/UnderlineNavItem.d.ts +6 -0
  16. package/dist/UnderlineNav/UnderlineNavItem.d.ts.map +1 -1
  17. package/dist/UnderlineNav/UnderlineNavItem.js +36 -39
  18. package/dist/UnderlineNav/UnderlineNavItem.module.css.js +1 -1
  19. package/dist/UnderlineNav/utils.d.ts +2 -0
  20. package/dist/UnderlineNav/utils.d.ts.map +1 -1
  21. package/dist/UnderlineNav/utils.js +2 -1
  22. package/dist/experimental/UnderlinePanels/UnderlinePanels-162f9aed.css +2 -0
  23. package/dist/experimental/UnderlinePanels/UnderlinePanels-162f9aed.css.map +1 -0
  24. package/dist/experimental/UnderlinePanels/UnderlinePanels.module.css.js +1 -1
  25. package/dist/internal/components/UnderlineTabbedInterface-1745a3d6.css +2 -0
  26. package/dist/internal/components/UnderlineTabbedInterface-1745a3d6.css.map +1 -0
  27. package/dist/internal/components/UnderlineTabbedInterface.d.ts +0 -1
  28. package/dist/internal/components/UnderlineTabbedInterface.d.ts.map +1 -1
  29. package/dist/internal/components/UnderlineTabbedInterface.js +66 -60
  30. package/dist/internal/components/UnderlineTabbedInterface.module.css.js +1 -1
  31. package/generated/components.json +2 -2
  32. package/package.json +1 -1
  33. package/dist/UnderlineNav/UnderlineNav-4344d9b0.css +0 -2
  34. package/dist/UnderlineNav/UnderlineNav-4344d9b0.css.map +0 -1
  35. package/dist/UnderlineNav/UnderlineNavItem-b65e8fd3.css +0 -2
  36. package/dist/UnderlineNav/UnderlineNavItem-b65e8fd3.css.map +0 -1
  37. package/dist/UnderlineNav/styles.d.ts +0 -16
  38. package/dist/UnderlineNav/styles.d.ts.map +0 -1
  39. package/dist/UnderlineNav/styles.js +0 -19
  40. package/dist/experimental/UnderlinePanels/UnderlinePanels-e4b325b9.css +0 -2
  41. package/dist/experimental/UnderlinePanels/UnderlinePanels-e4b325b9.css.map +0 -1
  42. package/dist/internal/components/UnderlineTabbedInterface-4197ee28.css +0 -2
  43. package/dist/internal/components/UnderlineTabbedInterface-4197ee28.css.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @primer/react
2
2
 
3
- ## 0.0.0-20260619134534
3
+ ## 0.0.0-20260619191426
4
4
 
5
- ### Patch Changes
5
+ ### Minor Changes
6
6
 
7
- - [#7935](https://github.com/primer/react/pull/7935) [`2765933`](https://github.com/primer/react/commit/276593387ec84f72aeba02a940b5e0a4d0a026a9) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - ConfirmationDialog: `useConfirm`/`confirm` now removes its host element from `document.body` after the dialog is closed, and uses a fresh host element per call, so the empty container no longer lingers or leaks into other components and tests
7
+ - [#7622](https://github.com/primer/react/pull/7622) [`4d8d5e6`](https://github.com/primer/react/commit/4d8d5e6b9b0b1d394d19154369f9c37eabe7cb87) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Refactors `UnderlineNav` overflow handling to use CSS-based overflow detection instead of JavaScript width measurements, eliminating layout shift (CLS) issues and improving performance. The overflow menu is now implemented with `ActionMenu`, and item registration uses a descendant registry instead of the `React.Children` API. Consumer-facing changes: items can now be wrapped in fragments or wrapper components; the current item may appear in the overflow menu when the viewport is narrow; and the overflow menu button is right-aligned.
8
+
9
+ ### Patch Changes
8
10
 
9
11
  - Fake entry to force publishing
10
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"useConfirm.d.ts","sourceRoot":"","sources":["../../src/ConfirmationDialog/useConfirm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAA;AAGxC,OAAO,EAAqB,KAAK,uBAAuB,EAAC,MAAM,sBAAsB,CAAA;AAErF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,GAAG;IAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;CAAC,CAAA;AAuBlG;;;;GAIG;AACH,wBAAgB,UAAU,cACa,cAAc,sBAIpD"}
1
+ {"version":3,"file":"useConfirm.d.ts","sourceRoot":"","sources":["../../src/ConfirmationDialog/useConfirm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAA;AAGxC,OAAO,EAAqB,KAAK,uBAAuB,EAAC,MAAM,sBAAsB,CAAA;AAIrF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,GAAG;IAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;CAAC,CAAA;AA0BlG;;;;GAIG;AACH,wBAAgB,UAAU,cACa,cAAc,sBAIpD"}
@@ -3,19 +3,23 @@ import { createRoot } from 'react-dom/client';
3
3
  import BaseStyles from '../BaseStyles.js';
4
4
  import { ConfirmationDialog } from './ConfirmationDialog.js';
5
5
 
6
+ let hostElement = null;
6
7
  async function confirm(options) {
7
8
  const {
8
9
  content,
9
10
  ...confirmationDialogProps
10
11
  } = options;
11
12
  return new Promise(resolve => {
12
- const hostElement = document.createElement('div');
13
- document.body.append(hostElement);
13
+ hostElement ||= document.createElement('div');
14
+ if (!hostElement.isConnected) document.body.append(hostElement);
14
15
  const root = createRoot(hostElement);
15
16
  const onClose = gesture => {
16
17
  root.unmount();
17
- hostElement.remove();
18
- resolve(gesture === 'confirm');
18
+ if (gesture === 'confirm') {
19
+ resolve(true);
20
+ } else {
21
+ resolve(false);
22
+ }
19
23
  };
20
24
  root.render(/*#__PURE__*/React.createElement(BaseStyles, null, /*#__PURE__*/React.createElement(ConfirmationDialog, {
21
25
  ...confirmationDialogProps,
@@ -0,0 +1,2 @@
1
+ .prc-UnderlineNav-UnderlineWrapper-GWONT{animation:prc-UnderlineNav-detect-overflow-6HuSH linear;animation-timeline:scroll(self block);--UnderlineNav_moreButton-visibility:hidden;--UnderlineNav_icons-display:inline}.prc-UnderlineNav-UnderlineWrapper-GWONT[data-hide-icons=true]{--UnderlineNav_icons-display:none}.prc-UnderlineNav-UnderlineWrapper-GWONT[data-has-overflow=true]{--UnderlineNav_moreButton-visibility:visible}@keyframes prc-UnderlineNav-detect-overflow-6HuSH{0%,to{--UnderlineNav_moreButton-visibility:visible;--UnderlineNav_icons-display:none}}.prc-UnderlineNav-ItemsList-oj8gN [data-component=icon]{display:var(--UnderlineNav_icons-display)}.prc-UnderlineNav-MoreButtonContainer-Dnrq6{align-items:center;display:flex;visibility:var(--UnderlineNav_moreButton-visibility)}.prc-UnderlineNav-OverflowMenuItem-7SG7M [aria-current]{position:relative}.prc-UnderlineNav-OverflowMenuItem-7SG7M [aria-current] .prc-UnderlineNav-OverflowMenuItemLabel-F80v6{font-weight:var(--base-text-weight-semibold,600)}.prc-UnderlineNav-OverflowMenuItem-7SG7M [aria-current]:after{background:var(--underlineNav-borderColor-active,#fd8c73);content:"";inset:var(--base-size-2,.125rem) auto var(--base-size-2,.125rem) 0;position:absolute;width:var(--base-size-2,.125rem)}.prc-UnderlineNav-MoreButtonDivider-dN0a-{border-left:var(--borderWidth-thin,.0625rem) solid var(--borderColor-muted,#d1d9e0b3);display:inline-block;height:var(--base-size-24,1.5rem);margin-inline:var(--base-size-4,.25rem);width:0}.prc-UnderlineNav-MoreButton-Y8soj{font-weight:var(--base-text-weight-normal,400);margin:0;position:relative}.prc-UnderlineNav-MoreButton-Y8soj>[data-component=trailingVisual]{margin-left:0}.prc-UnderlineNav-MoreButton-Y8soj[data-current=true]{font-weight:var(--base-text-weight-semibold,600)}.prc-UnderlineNav-MoreButton-Y8soj[data-current=true]:after{background-color:var(--underlineNav-borderColor-active,var(--color-primer-border-active,#fd8c73));content:"";height:2px;inset:auto 0 0;margin-bottom:calc(var(--base-size-8,.5rem)*-1);pointer-events:none;position:absolute}@media (forced-colors:active){.prc-UnderlineNav-MoreButton-Y8soj[data-current=true]:after{background-color:LinkText}}
2
+ /*# sourceMappingURL=UnderlineNav-263b4e8f.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/UnderlineNav/UnderlineNav.module.css.js"],"names":[],"mappings":"AAAA,yCAIE,uDAAiC,CACjC,qCAAsC,CAEtC,2CAA4C,CAC5C,mCASF,CAPE,+DACE,iCACF,CAEA,iEACE,4CACF,CAGF,kDACE,MAEE,4CAA6C,CAC7C,iCACF,CACF,CAEA,wDACE,yCACF,CAEA,4CAGE,kBAAmB,CAFnB,YAAa,CACb,oDAEF,CAEA,wDACE,iBAcF,CAZE,sGACE,gDACF,CAEA,8DAME,yDAAkD,CALlD,UAAW,CAGX,kEAAmD,CADnD,iBAAkB,CADlB,gCAKF,CAGF,0CAEE,qFAAmE,CADnE,oBAAqB,CAIrB,iCAA2B,CAD3B,uCAAiC,CADjC,OAGF,CAEA,mCAEE,8CAA2C,CAD3C,QAAS,CAET,iBA2BF,CAzBE,mEACE,aACF,CAIA,sDACE,gDAiBF,CAfE,4DAQE,iGAAoG,CAFpG,UAAW,CAFX,UAAW,CAFX,cAAe,CACf,+CAA4C,CAE5C,mBAAoB,CAJpB,iBAaF,CAJE,8BAVF,4DAYI,yBAEJ,CADE","file":"UnderlineNav-263b4e8f.css","sourcesContent":[".UnderlineWrapper {\n /* Progressive enhancement: Detect overflow using scroll-based animations.\n The idiomatic way would be a scroll-state container query but browser support\n is slightly better for animations. */\n animation: detect-overflow linear;\n animation-timeline: scroll(self block);\n\n --UnderlineNav_moreButton-visibility: hidden;\n --UnderlineNav_icons-display: inline;\n\n &[data-hide-icons='true'] {\n --UnderlineNav_icons-display: none;\n }\n\n &[data-has-overflow='true'] {\n --UnderlineNav_moreButton-visibility: visible;\n }\n}\n\n@keyframes detect-overflow {\n 0%,\n 100% {\n --UnderlineNav_moreButton-visibility: visible;\n --UnderlineNav_icons-display: none;\n }\n}\n\n.ItemsList [data-component='icon'] {\n display: var(--UnderlineNav_icons-display);\n}\n\n.MoreButtonContainer {\n display: flex;\n visibility: var(--UnderlineNav_moreButton-visibility);\n align-items: center;\n}\n\n.OverflowMenuItem [aria-current] {\n position: relative;\n\n .OverflowMenuItemLabel {\n font-weight: var(--base-text-weight-semibold);\n }\n\n &::after {\n content: '';\n width: var(--base-size-2);\n position: absolute;\n inset: var(--base-size-2) auto var(--base-size-2) 0;\n /* stylelint-disable-next-line primer/colors */\n background: var(--underlineNav-borderColor-active);\n }\n}\n\n.MoreButtonDivider {\n display: inline-block;\n border-left: var(--borderWidth-thin) solid var(--borderColor-muted);\n width: 0;\n margin-inline: var(--base-size-4);\n height: var(--base-size-24);\n}\n\n.MoreButton {\n margin: 0; /* reset Safari extra margin */\n font-weight: var(--base-text-weight-normal);\n position: relative;\n\n & > [data-component='trailingVisual'] {\n margin-left: 0;\n }\n\n /* When the current item has overflowed into the menu, style the overflow\n anchor so it looks like the current item (semibold text + active underline). */\n &[data-current='true'] {\n font-weight: var(--base-text-weight-semibold);\n\n &::after {\n position: absolute;\n inset: auto 0 0;\n margin-bottom: calc(-1 * var(--base-size-8));\n height: 2px;\n pointer-events: none;\n content: '';\n /* stylelint-disable-next-line primer/colors */\n background-color: var(--underlineNav-borderColor-active, var(--color-primer-border-active, #fd8c73));\n\n @media (forced-colors: active) {\n /* Support for Windows Forced Color Mode https://learn.microsoft.com/en-us/fluent-ui/web-components/design-system/high-contrast */\n background-color: LinkText;\n }\n }\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import type React from 'react';
2
2
  export type UnderlineNavProps = {
3
3
  children: React.ReactNode;
4
4
  'aria-label'?: React.AriaAttributes['aria-label'];
@@ -15,6 +15,5 @@ export type UnderlineNavProps = {
15
15
  */
16
16
  variant?: 'inset' | 'flush';
17
17
  };
18
- export declare const MORE_BTN_WIDTH = 86;
19
18
  export declare const UnderlineNav: React.ForwardRefExoticComponent<UnderlineNavProps & React.RefAttributes<unknown>>;
20
19
  //# sourceMappingURL=UnderlineNav.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnderlineNav.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNav.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkD,MAAM,OAAO,CAAA;AAqBtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;IACjD,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAC5B,CAAA;AAGD,eAAO,MAAM,cAAc,KAAK,CAAA;AAsGhC,eAAO,MAAM,YAAY,mFA0SxB,CAAA"}
1
+ {"version":3,"file":"UnderlineNav.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNav.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgB9B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;IACjD,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,YAAY,mFAiIxB,CAAA"}
@@ -1,117 +1,19 @@
1
- import React, { forwardRef, useRef, useState, useCallback } from 'react';
2
- import { useDevOnlyEffect } from '../internal/hooks/useDevOnlyEffect.js';
3
- import { UnderlineNavContext } from './UnderlineNavContext.js';
4
- import { useResizeObserver } from '../hooks/useResizeObserver.js';
1
+ import { forwardRef, useRef, useState, useMemo } from 'react';
5
2
  import VisuallyHidden from '../_VisuallyHidden.js';
6
- import { dividerStyles, baseMenuMinWidth, menuItemStyles } from './styles.js';
7
- import { UnderlineWrapper, UnderlineItemList, LoadingCounter, GAP } from '../internal/components/UnderlineTabbedInterface.js';
8
- import { TriangleDownIcon } from '@primer/octicons-react';
9
- import { useOnEscapePress } from '../hooks/useOnEscapePress.js';
10
- import { useOnOutsideClick } from '../hooks/useOnOutsideClick.js';
11
- import { useId } from '../hooks/useId.js';
12
3
  import { ActionList } from '../ActionList/index.js';
4
+ import { UnderlineWrapper, UnderlineItemList, LoadingCounter } from '../internal/components/UnderlineTabbedInterface.js';
13
5
  import { invariant } from '../utils/invariant.js';
14
6
  import classes from './UnderlineNav.module.css.js';
15
- import { getAnchoredPosition } from '@primer/behaviors';
16
- import { getValidChildren } from './utils.js';
17
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
18
- import { ButtonComponent } from '../Button/Button.js';
7
+ import { UnderlineNavContext } from './UnderlineNavContext.js';
8
+ import { UnderlineNavItemsRegistry } from './UnderlineNavItem.js';
9
+ import { clsx } from 'clsx';
10
+ import { useDevOnlyEffect } from '../internal/hooks/useDevOnlyEffect.js';
11
+ import { isCurrent, getValidChildren } from './utils.js';
12
+ import { jsxs, jsx } from 'react/jsx-runtime';
13
+ import { SkeletonText } from '../SkeletonText/SkeletonText.js';
19
14
  import CounterLabel from '../CounterLabel/CounterLabel.js';
15
+ import { ActionMenu } from '../ActionMenu/ActionMenu.js';
20
16
 
21
- // When page is loaded, we don't have ref for the more button as it is not on the DOM yet.
22
- // However, we need to calculate number of possible items when the more button present as well. So using the width of the more button as a constant.
23
- const MORE_BTN_WIDTH = 86;
24
- // The height is needed to make sure we don't have a layout shift when the more button is the only item in the nav.
25
- const MORE_BTN_HEIGHT = 45;
26
- const overflowEffect = (navWidth, moreMenuWidth, childArray, childWidthArray, noIconChildWidthArray, updateListAndMenu) => {
27
- let iconsVisible = true;
28
- if (childWidthArray.length === 0) {
29
- updateListAndMenu({
30
- items: childArray,
31
- menuItems: []
32
- }, iconsVisible, false);
33
- return;
34
- }
35
- const numberOfItemsPossible = calculatePossibleItems(childWidthArray, navWidth);
36
- const numberOfItemsWithoutIconPossible = calculatePossibleItems(noIconChildWidthArray, navWidth);
37
- // We need to take more menu width into account when calculating the number of items possible
38
- const numberOfItemsPossibleWithMoreMenu = calculatePossibleItems(noIconChildWidthArray, navWidth, moreMenuWidth || MORE_BTN_WIDTH);
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
- const items = [];
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
- const menuItems = [];
43
-
44
- // First, we check if we can fit all the items with their icons
45
- if (childArray.length <= numberOfItemsPossible) {
46
- items.push(...childArray);
47
- } else if (childArray.length <= numberOfItemsWithoutIconPossible) {
48
- // if we can't fit all the items with their icons, we check if we can fit all the items without their icons
49
- iconsVisible = false;
50
- items.push(...childArray);
51
- } else {
52
- // if we can't fit all the items without their icons, we keep the icons hidden and show the ones that doesn't fit into the list in the overflow menu
53
- iconsVisible = false;
54
-
55
- /* Below is an accessibility requirement. Never show only one item in the overflow menu.
56
- * If there is only one item left to display in the overflow menu according to the calculation,
57
- * we need to pull another item from the list into the overflow menu.
58
- */
59
- const numberOfItemsInMenu = childArray.length - numberOfItemsPossibleWithMoreMenu;
60
- const numberOfListItems = numberOfItemsInMenu === 1 ? numberOfItemsPossibleWithMoreMenu - 1 : numberOfItemsPossibleWithMoreMenu;
61
- for (const [index, child] of childArray.entries()) {
62
- if (index < numberOfListItems) {
63
- items.push(child);
64
- } else {
65
- const ariaCurrent = child.props['aria-current'];
66
- const isCurrent = Boolean(ariaCurrent) && ariaCurrent !== 'false';
67
- // We need to make sure to keep the selected item always visible.
68
- // To do that, we swap the selected item with the last item in the list to make it visible. (When there is at least 1 item in the list to swap.)
69
- if (isCurrent && numberOfListItems > 0) {
70
- // If selected item couldn't make in to the list, we swap it with the last item in the list.
71
- const indexToReplaceAt = numberOfListItems - 1; // because we are replacing the last item in the list
72
- // splice method modifies the array by removing 1 item here at the given index and replace it with the "child" element then returns the removed item.
73
- const propsectiveAction = items.splice(indexToReplaceAt, 1, child)[0];
74
- menuItems.push(propsectiveAction);
75
- } else {
76
- menuItems.push(child);
77
- }
78
- }
79
- }
80
- }
81
- updateListAndMenu({
82
- items,
83
- menuItems
84
- }, iconsVisible, true);
85
- };
86
- const calculatePossibleItems = (childWidthArray, navWidth, moreMenuWidth = 0) => {
87
- const widthToFit = navWidth - moreMenuWidth;
88
- let breakpoint = childWidthArray.length; // assume all items will fit
89
- let sumsOfChildWidth = 0;
90
- for (const [index, childWidth] of childWidthArray.entries()) {
91
- sumsOfChildWidth = sumsOfChildWidth + childWidth.width + GAP;
92
- if (sumsOfChildWidth > widthToFit) {
93
- breakpoint = index;
94
- break;
95
- } else {
96
- continue;
97
- }
98
- }
99
- return breakpoint;
100
- };
101
-
102
- // Inline styles converted from baseMenuStyles for use as CSSProperties
103
- const baseMenuInlineStyles = {
104
- position: 'absolute',
105
- zIndex: 1,
106
- top: '90%',
107
- boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
108
- borderRadius: 12,
109
- background: 'var(--overlay-bgColor)',
110
- listStyle: 'none',
111
- minWidth: `${baseMenuMinWidth}px`,
112
- maxWidth: '640px',
113
- right: 0
114
- };
115
17
  const UnderlineNav = /*#__PURE__*/forwardRef(({
116
18
  as = 'nav',
117
19
  'aria-label': ariaLabel,
@@ -120,259 +22,111 @@ const UnderlineNav = /*#__PURE__*/forwardRef(({
120
22
  className,
121
23
  children
122
24
  }, forwardedRef) => {
123
- var _listRef$current2;
25
+ var _registeredItems$entr;
124
26
  const backupRef = useRef(null);
125
27
  const navRef = forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : backupRef;
126
28
  const listRef = useRef(null);
127
- const moreMenuRef = useRef(null);
128
- const moreMenuBtnRef = useRef(null);
129
- const containerRef = React.useRef(null);
130
- const disclosureWidgetId = useId();
131
- const [isWidgetOpen, setIsWidgetOpen] = useState(false);
132
- const [iconsVisible, setIconsVisible] = useState(true);
133
- const [childWidthArray, setChildWidthArray] = useState([]);
134
- const [noIconChildWidthArray, setNoIconChildWidthArray] = useState([]);
135
- // Track whether the initial overflow calculation is complete to prevent CLS
136
- const [isOverflowMeasured, setIsOverflowMeasured] = useState(false);
137
- const validChildren = getValidChildren(children);
138
29
 
139
- // Responsive props object manages which items are in the list and which items are in the menu.
140
- const [responsiveProps, setResponsiveProps] = useState({
141
- items: validChildren,
142
- menuItems: []
143
- });
30
+ /** Tracks whether any item has ever overflowed for the lifecycle of this component. Used to prevent flickering. */
31
+ const [hasEverOverflowed, setHasOverflowed] = useState(false);
32
+ const [registeredItems, setRegisteredItems] = UnderlineNavItemsRegistry.useRegistryState();
33
+ const overflowMenuItems = Array.from((_registeredItems$entr = registeredItems === null || registeredItems === void 0 ? void 0 : registeredItems.entries()) !== null && _registeredItems$entr !== void 0 ? _registeredItems$entr : []).filter(entry => entry[1] !== null);
34
+ const isOverflowing = overflowMenuItems.length > 0;
35
+ if (isOverflowing && !hasEverOverflowed) setHasOverflowed(true);
144
36
 
145
- // Make sure to have the fresh props data for list items when children are changed (keeping aria-current up-to-date)
146
- const listItems = responsiveProps.items.map(item => {
147
- var _validChildren$find;
148
- return (_validChildren$find = validChildren.find(child => child.key === item.key)) !== null && _validChildren$find !== void 0 ? _validChildren$find : item;
149
- });
150
-
151
- // Make sure to have the fresh props data for menu items when children are changed (keeping aria-current up-to-date)
152
- const menuItems = responsiveProps.menuItems.map(menuItem => {
153
- var _validChildren$find2;
154
- return (_validChildren$find2 = validChildren.find(child => child.key === menuItem.key)) !== null && _validChildren$find2 !== void 0 ? _validChildren$find2 : menuItem;
155
- });
156
- // This is the case where the viewport is too narrow to show any list item with the more menu. In this case, we only show the dropdown
157
- const onlyMenuVisible = responsiveProps.items.length === 0;
37
+ // Find the current item if it has overflowed into the menu, so we can reflect
38
+ // its "current" state on the overflow menu anchor.
39
+ const overflowingCurrentItem = overflowMenuItems.some(([, itemProps]) => isCurrent(itemProps));
40
+ const validChildren = getValidChildren(children);
158
41
  useDevOnlyEffect(() => {
159
42
  // Address illegal state where there are multiple items that have `aria-current='page'` attribute
160
- const activeElements = validChildren.filter(child => {
161
- return child.props['aria-current'] !== undefined;
162
- });
43
+ const activeElements = validChildren.filter(child => isCurrent(child.props));
163
44
  !(activeElements.length <= 1) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Only one current element is allowed') : invariant(false) : void 0;
164
45
  !ariaLabel ? process.env.NODE_ENV !== "production" ? invariant(false, 'Use the `aria-label` prop to provide an accessible label for assistive technology') : invariant(false) : void 0;
165
46
  }, [validChildren, ariaLabel]);
166
- function getItemsWidth(itemText) {
167
- var _noIconChildWidthArra, _noIconChildWidthArra2;
168
- return (_noIconChildWidthArra = (_noIconChildWidthArra2 = noIconChildWidthArray.find(item => item.text === itemText)) === null || _noIconChildWidthArra2 === void 0 ? void 0 : _noIconChildWidthArra2.width) !== null && _noIconChildWidthArra !== void 0 ? _noIconChildWidthArra : 0;
169
- }
170
- const swapMenuItemWithListItem = (prospectiveListItem, indexOfProspectiveListItem, event, callback) => {
171
- var _navRef$current$getBo, _navRef$current, _listRef$current$getB, _listRef$current;
172
- // get the selected menu item's width
173
- const widthToFitIntoList = getItemsWidth(prospectiveListItem.props.children);
174
- // Check if there is any empty space on the right side of the list
175
- const availableSpace = ((_navRef$current$getBo = (_navRef$current = navRef.current) === null || _navRef$current === void 0 ? void 0 : _navRef$current.getBoundingClientRect().width) !== null && _navRef$current$getBo !== void 0 ? _navRef$current$getBo : 0) - ((_listRef$current$getB = (_listRef$current = listRef.current) === null || _listRef$current === void 0 ? void 0 : _listRef$current.getBoundingClientRect().width) !== null && _listRef$current$getB !== void 0 ? _listRef$current$getB : 0);
176
-
177
- // Calculate how many items need to be pulled in to the menu to make room for the selected menu item
178
- // I.e. if we need to pull 2 items in (index 0 and index 1), breakpoint (index) will return 1.
179
- const index = getBreakpointForItemSwapping(widthToFitIntoList, availableSpace);
180
- const indexToSliceAt = responsiveProps.items.length - 1 - index;
181
- // Form the new list of items
182
- const itemsLeftInList = [...responsiveProps.items].slice(0, indexToSliceAt);
183
- const updatedItemList = [...itemsLeftInList, prospectiveListItem];
184
- // Form the new menu items
185
- const itemsToAddToMenu = [...responsiveProps.items].slice(indexToSliceAt);
186
- const updatedMenuItems = [...menuItems];
187
- // Add itemsToAddToMenu array's items to the menu at the index of the prospectiveListItem and remove 1 count of items (prospectiveListItem)
188
- updatedMenuItems.splice(indexOfProspectiveListItem, 1, ...itemsToAddToMenu);
189
- callback({
190
- items: updatedItemList,
191
- menuItems: updatedMenuItems
192
- }, false, true);
193
- };
194
- // How many items do we need to pull in to the menu to make room for the selected menu item.
195
- function getBreakpointForItemSwapping(widthToFitIntoList, availableSpace) {
196
- let widthToSwap = 0;
197
- let breakpoint = 0;
198
- for (const [index, item] of [...responsiveProps.items].reverse().entries()) {
199
- widthToSwap += getItemsWidth(item.props.children);
200
- if (widthToFitIntoList < widthToSwap + availableSpace) {
201
- breakpoint = index;
202
- break;
203
- }
204
- }
205
- return breakpoint;
206
- }
207
- const updateListAndMenu = useCallback((props, displayIcons, overflowMeasured) => {
208
- setResponsiveProps(props);
209
- setIconsVisible(displayIcons);
210
- if (overflowMeasured) {
211
- setIsOverflowMeasured(true);
212
- }
213
- }, []);
214
- const setChildrenWidth = useCallback(size => {
215
- setChildWidthArray(arr => {
216
- const newArr = [...arr, size];
217
- return newArr;
218
- });
219
- }, []);
220
- const setNoIconChildrenWidth = useCallback(size => {
221
- setNoIconChildWidthArray(arr => {
222
- const newArr = [...arr, size];
223
- return newArr;
224
- });
225
- }, []);
226
- const closeOverlay = React.useCallback(() => {
227
- setIsWidgetOpen(false);
228
- }, [setIsWidgetOpen]);
229
- const focusOnMoreMenuBtn = React.useCallback(() => {
230
- var _moreMenuBtnRef$curre;
231
- (_moreMenuBtnRef$curre = moreMenuBtnRef.current) === null || _moreMenuBtnRef$curre === void 0 ? void 0 : _moreMenuBtnRef$curre.focus();
232
- }, []);
233
- const onAnchorClick = useCallback(event => {
234
- if (event.defaultPrevented || event.button !== 0) {
235
- return;
236
- }
237
- setIsWidgetOpen(isWidgetOpen => !isWidgetOpen);
238
- }, []);
239
- useOnEscapePress(event => {
240
- if (isWidgetOpen) {
241
- event.preventDefault();
242
- closeOverlay();
243
- focusOnMoreMenuBtn();
244
- }
245
- }, [isWidgetOpen]);
246
- useOnOutsideClick({
247
- onClickOutside: closeOverlay,
248
- containerRef,
249
- ignoreClickRefs: [moreMenuBtnRef]
250
- });
251
- useResizeObserver(resizeObserverEntries => {
252
- var _moreMenuRef$current$, _moreMenuRef$current;
253
- const navWidth = resizeObserverEntries[0].contentRect.width;
254
- const moreMenuWidth = (_moreMenuRef$current$ = (_moreMenuRef$current = moreMenuRef.current) === null || _moreMenuRef$current === void 0 ? void 0 : _moreMenuRef$current.getBoundingClientRect().width) !== null && _moreMenuRef$current$ !== void 0 ? _moreMenuRef$current$ : 0;
255
- navWidth !== 0 && overflowEffect(navWidth, moreMenuWidth, validChildren, childWidthArray, noIconChildWidthArray, updateListAndMenu);
256
- }, navRef);
257
-
258
- // Compute menuInlineStyles if needed
259
- let menuInlineStyles = {
260
- ...baseMenuInlineStyles
261
- };
262
- if (containerRef.current && listRef.current) {
263
- const {
264
- left
265
- } = getAnchoredPosition(containerRef.current, listRef.current, {
266
- align: 'start',
267
- side: 'outside-bottom'
268
- });
269
- menuInlineStyles = {
270
- ...baseMenuInlineStyles,
271
- right: undefined,
272
- left
273
- };
274
- }
47
+ const contextValue = useMemo(() => ({
48
+ loadingCounters
49
+ }), [loadingCounters]);
275
50
  return /*#__PURE__*/jsxs(UnderlineNavContext.Provider, {
276
- value: {
277
- setChildrenWidth,
278
- setNoIconChildrenWidth,
279
- loadingCounters,
280
- iconsVisible
281
- },
51
+ value: contextValue,
282
52
  children: [ariaLabel && /*#__PURE__*/jsx(VisuallyHidden, {
283
53
  as: "h2",
284
54
  children: `${ariaLabel} navigation`
285
- }), /*#__PURE__*/jsx(UnderlineWrapper, {
55
+ }), /*#__PURE__*/jsxs(UnderlineWrapper, {
286
56
  as: as,
287
57
  "aria-label": ariaLabel,
288
- className: className,
58
+ className: clsx(classes.UnderlineWrapper, className),
289
59
  ref: navRef,
290
60
  "data-variant": variant,
291
- "data-overflow-measured": isOverflowMeasured ? 'true' : 'false',
292
- children: /*#__PURE__*/jsxs(UnderlineItemList, {
61
+ "data-overflow-mode": "wrap"
62
+ // Force icons to stay hidden, avoiding flickering as icons create/remove overflow
63
+ ,
64
+ "data-hide-icons": hasEverOverflowed ? 'true' : undefined
65
+ // Ensure button is shown (after initial render) on browsers that don't support scroll-driven animations
66
+ ,
67
+ "data-has-overflow": isOverflowing ? 'true' : undefined,
68
+ children: [/*#__PURE__*/jsx(UnderlineItemList, {
293
69
  ref: listRef,
294
70
  role: "list",
295
- children: [listItems, menuItems.length > 0 && /*#__PURE__*/jsxs("li", {
296
- ref: moreMenuRef,
297
- style: {
298
- display: 'flex',
299
- alignItems: 'center',
300
- height: `${MORE_BTN_HEIGHT}px`
301
- },
302
- children: [!onlyMenuVisible && /*#__PURE__*/jsx("div", {
303
- style: dividerStyles
304
- }), /*#__PURE__*/jsx(ButtonComponent, {
305
- ref: moreMenuBtnRef,
71
+ className: classes.ItemsList,
72
+ children: /*#__PURE__*/jsx(UnderlineNavItemsRegistry.Provider, {
73
+ setRegistry: setRegisteredItems,
74
+ children: children
75
+ })
76
+ }), /*#__PURE__*/jsxs("div", {
77
+ className: classes.MoreButtonContainer,
78
+ children: [/*#__PURE__*/jsx("div", {
79
+ className: classes.MoreButtonDivider
80
+ }), /*#__PURE__*/jsxs(ActionMenu, {
81
+ children: [/*#__PURE__*/jsx(ActionMenu.Button, {
306
82
  className: classes.MoreButton,
307
- "aria-controls": disclosureWidgetId,
308
- "aria-expanded": isWidgetOpen,
309
- onClick: onAnchorClick,
310
- trailingAction: TriangleDownIcon,
311
- children: /*#__PURE__*/jsx("span", {
312
- children: onlyMenuVisible ? /*#__PURE__*/jsxs(Fragment, {
313
- children: [/*#__PURE__*/jsxs(VisuallyHidden, {
314
- as: "span",
315
- children: [`${ariaLabel}`, "\xA0"]
316
- }), "Menu"]
317
- }) : /*#__PURE__*/jsxs(Fragment, {
318
- children: ["More", /*#__PURE__*/jsxs(VisuallyHidden, {
319
- as: "span",
320
- children: ["\xA0", `${ariaLabel} items`]
321
- })]
322
- })
83
+ variant: "invisible",
84
+ "data-component": "overflow-menu-button",
85
+ "data-current": overflowingCurrentItem ? 'true' : undefined,
86
+ "aria-label": overflowingCurrentItem ? `More items, including current item` : undefined,
87
+ children: /*#__PURE__*/jsxs("span", {
88
+ children: ["More", /*#__PURE__*/jsx(VisuallyHidden, {
89
+ as: "span",
90
+ children: " items"
91
+ })]
323
92
  })
324
- }), /*#__PURE__*/jsx(ActionList, {
325
- selectionVariant: "single",
326
- ref: containerRef,
327
- id: disclosureWidgetId,
328
- style: {
329
- ...((_listRef$current2 = listRef.current) !== null && _listRef$current2 !== void 0 && _listRef$current2.clientWidth && listRef.current.clientWidth >= baseMenuMinWidth ? baseMenuInlineStyles : menuInlineStyles),
330
- display: isWidgetOpen ? 'block' : 'none'
331
- },
332
- children: menuItems.map((menuItem, index) => {
333
- const {
334
- children: menuItemChildren,
335
- counter,
336
- 'aria-current': ariaCurrent,
337
- onSelect,
338
- ...menuItemProps
339
- } = menuItem.props;
340
-
341
- // This logic is used to pop the selected item out of the menu and into the list when the navigation is control externally
342
- if (Boolean(ariaCurrent) && ariaCurrent !== 'false') {
343
- const event = new MouseEvent('click');
344
- !onlyMenuVisible && swapMenuItemWithListItem(menuItem, index,
345
- // @ts-ignore - not a big deal because it is internally creating an event but ask help
346
- event, updateListAndMenu);
347
- }
348
- return /*#__PURE__*/jsx(ActionList.LinkItem, {
349
- style: menuItemStyles,
350
- onClick: event => {
351
- // When there are no items in the list, do not run the swap function as we want to keep everything in the menu.
352
- !onlyMenuVisible && swapMenuItemWithListItem(menuItem, index, event, updateListAndMenu);
353
- closeOverlay();
354
- focusOnMoreMenuBtn();
355
- // fire onSelect event that comes from the UnderlineNav.Item (if it is defined)
356
- typeof onSelect === 'function' && onSelect(event);
357
- },
358
- ...menuItemProps,
359
- children: /*#__PURE__*/jsxs("span", {
360
- className: classes.MenuItemContent,
361
- children: [menuItemChildren, loadingCounters ? /*#__PURE__*/jsx(LoadingCounter, {}) : counter !== undefined && /*#__PURE__*/jsx("span", {
362
- "data-component": "counter",
363
- children: /*#__PURE__*/jsx(CounterLabel, {
364
- children: counter
93
+ }), /*#__PURE__*/jsx(ActionMenu.Overlay, {
94
+ children: /*#__PURE__*/jsx(ActionList, {
95
+ children: registeredItems === undefined ? /*#__PURE__*/jsx(ActionList.Item, {
96
+ children: /*#__PURE__*/jsx(SkeletonText, {})
97
+ }) : overflowMenuItems.map(([key, allProps]) => {
98
+ const {
99
+ children: menuItemChildren,
100
+ counter,
101
+ onSelect,
102
+ ...menuItemProps
103
+ } = allProps;
104
+ return /*#__PURE__*/jsxs(ActionList.LinkItem, {
105
+ className: classes.OverflowMenuItem,
106
+ onClick: event => onSelect === null || onSelect === void 0 ? void 0 : onSelect(event),
107
+ ...menuItemProps,
108
+ children: [/*#__PURE__*/jsx("span", {
109
+ className: classes.OverflowMenuItemLabel,
110
+ children: menuItemChildren
111
+ }), loadingCounters ? /*#__PURE__*/jsx(ActionList.TrailingVisual, {
112
+ children: /*#__PURE__*/jsx(LoadingCounter, {})
113
+ }) : counter !== undefined && /*#__PURE__*/jsx(ActionList.TrailingVisual, {
114
+ children: /*#__PURE__*/jsx("span", {
115
+ "data-component": "counter",
116
+ children: /*#__PURE__*/jsx(CounterLabel, {
117
+ children: counter
118
+ })
365
119
  })
366
120
  })]
367
- })
368
- }, menuItemChildren);
121
+ }, key);
122
+ })
369
123
  })
370
124
  })]
371
125
  })]
372
- })
126
+ })]
373
127
  })]
374
128
  });
375
129
  });
376
130
  UnderlineNav.displayName = 'UnderlineNav';
377
131
 
378
- export { MORE_BTN_WIDTH, UnderlineNav };
132
+ export { UnderlineNav };
@@ -1,5 +1,5 @@
1
- import './UnderlineNav-4344d9b0.css';
1
+ import './UnderlineNav-263b4e8f.css';
2
2
 
3
- var classes = {"MenuItemContent":"prc-UnderlineNav-MenuItemContent-3J7gB","MoreButton":"prc-UnderlineNav-MoreButton-Y8soj"};
3
+ var classes = {"UnderlineWrapper":"prc-UnderlineNav-UnderlineWrapper-GWONT","detect-overflow":"prc-UnderlineNav-detect-overflow-6HuSH","ItemsList":"prc-UnderlineNav-ItemsList-oj8gN","MoreButtonContainer":"prc-UnderlineNav-MoreButtonContainer-Dnrq6","OverflowMenuItem":"prc-UnderlineNav-OverflowMenuItem-7SG7M","OverflowMenuItemLabel":"prc-UnderlineNav-OverflowMenuItemLabel-F80v6","MoreButtonDivider":"prc-UnderlineNav-MoreButtonDivider-dN0a-","MoreButton":"prc-UnderlineNav-MoreButton-Y8soj"};
4
4
 
5
5
  export { classes as default };
@@ -1,14 +1,4 @@
1
- import type React from 'react';
2
- export declare const UnderlineNavContext: React.Context<{
3
- setChildrenWidth: React.Dispatch<{
4
- text: string;
5
- width: number;
6
- }>;
7
- setNoIconChildrenWidth: React.Dispatch<{
8
- text: string;
9
- width: number;
10
- }>;
1
+ export declare const UnderlineNavContext: import("react").Context<{
11
2
  loadingCounters: boolean;
12
- iconsVisible: boolean;
13
3
  }>;
14
4
  //# sourceMappingURL=UnderlineNavContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnderlineNavContext.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNavContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,eAAO,MAAM,mBAAmB;sBACZ,KAAK,CAAC,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;4BACvC,KAAK,CAAC,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;qBACpD,OAAO;kBACV,OAAO;EAMrB,CAAA"}
1
+ {"version":3,"file":"UnderlineNavContext.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNavContext.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB;qBACb,OAAO;EAGxB,CAAA"}
@@ -1,10 +1,7 @@
1
1
  import { createContext } from 'react';
2
2
 
3
3
  const UnderlineNavContext = /*#__PURE__*/createContext({
4
- setChildrenWidth: () => null,
5
- setNoIconChildrenWidth: () => null,
6
- loadingCounters: false,
7
- iconsVisible: true
4
+ loadingCounters: false
8
5
  });
9
6
 
10
7
  export { UnderlineNavContext };
@@ -0,0 +1,2 @@
1
+ .prc-UnderlineNav-UnderlineNavItem-syRjR{align-items:center;display:flex;flex-direction:column;overflow:hidden}.prc-UnderlineNav-UnderlineNavItem-syRjR[aria-hidden]{visibility:hidden}
2
+ /*# sourceMappingURL=UnderlineNavItem-402cd41c.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/UnderlineNav/UnderlineNavItem.module.css.js"],"names":[],"mappings":"AAAA,yCAGE,kBAAmB,CAFnB,YAAa,CACb,qBAAsB,CAEtB,eAOF,CALE,sDAGE,iBACF","file":"UnderlineNavItem-402cd41c.css","sourcesContent":[".UnderlineNavItem {\n display: flex;\n flex-direction: column;\n align-items: center;\n overflow: hidden;\n\n &[aria-hidden] {\n /* Overflowing items will already be clipped out of view, but might as well\n also hide them for performance and to ensure they can't accidentally appear */\n visibility: hidden;\n }\n}\n"]}
@@ -43,5 +43,11 @@ export type UnderlineNavItemProps = {
43
43
  */
44
44
  counter?: number | string;
45
45
  } & LinkProps;
46
+ /** Registry of currently-overflowing underline items. If an item is not overflowing, its value will be `null`. */
47
+ export declare const UnderlineNavItemsRegistry: {
48
+ Provider: ({ children, setRegistry }: import("../utils/descendant-registry").ProviderProps<UnderlineNavItemProps | null>) => React.JSX.Element;
49
+ useRegistryState: () => [ReadonlyMap<string, UnderlineNavItemProps | null> | undefined, React.Dispatch<React.SetStateAction<ReadonlyMap<string, UnderlineNavItemProps | null> | undefined>>];
50
+ useRegisterDescendant: (value: UnderlineNavItemProps | null) => string;
51
+ };
46
52
  export declare const UnderlineNavItem: PolymorphicForwardRefComponent<"a", UnderlineNavItemProps>;
47
53
  //# sourceMappingURL=UnderlineNavItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnderlineNavItem.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNavItem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAuC,MAAM,OAAO,CAAA;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AACrD,OAAO,KAAK,EAAC,mBAAmB,IAAI,8BAA8B,EAAC,MAAM,sBAAsB,CAAA;AAO/F,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,gBAAgB,CAAC,CAAA;CACjF,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAExG;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;IAE5F;;;OAGG;IAEH,IAAI,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAEnE;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,YAAY,CAAA;IAElC;;QAEI;IACJ,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,GAAG,CAAA;IAE5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC1B,GAAG,SAAS,CAAA;AAEb,eAAO,MAAM,gBAAgB,EAgFxB,8BAA8B,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA"}
1
+ {"version":3,"file":"UnderlineNavItem.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/UnderlineNavItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0E,MAAM,OAAO,CAAA;AAC9F,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AACrD,OAAO,KAAK,EAAC,mBAAmB,IAAI,8BAA8B,EAAC,MAAM,sBAAsB,CAAA;AAO/F,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,gBAAgB,CAAC,CAAA;CACjF,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAExG;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;IAE5F;;;OAGG;IAEH,IAAI,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAEnE;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,YAAY,CAAA;IAElC;;QAEI;IACJ,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,GAAG,CAAA;IAE5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC1B,GAAG,SAAS,CAAA;AAEb,kHAAkH;AAClH,eAAO,MAAM,yBAAyB;;;;CAA2D,CAAA;AAEjG,eAAO,MAAM,gBAAgB,EA0EvB,8BAA8B,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA"}
@@ -1,46 +1,41 @@
1
- import React, { forwardRef, useRef, useContext } from 'react';
1
+ import React, { forwardRef, useRef, useContext, useSyncExternalStore, useCallback } from 'react';
2
2
  import { UnderlineNavContext } from './UnderlineNavContext.js';
3
- import useIsomorphicLayoutEffect from '../utils/useIsomorphicLayoutEffect.js';
4
3
  import { UnderlineItem } from '../internal/components/UnderlineTabbedInterface.js';
5
4
  import classes from './UnderlineNavItem.module.css.js';
5
+ import { createDescendantRegistry } from '../utils/descendant-registry.js';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
8
- const UnderlineNavItem = /*#__PURE__*/forwardRef(({
9
- as: Component = 'a',
10
- href = '#',
11
- children,
12
- counter,
13
- onSelect,
14
- 'aria-current': ariaCurrent,
15
- icon: Icon,
16
- leadingVisual,
17
- ...props
18
- }, forwardedRef) => {
19
- const backupRef = useRef(null);
20
- const ref = forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : backupRef;
8
+ /** Registry of currently-overflowing underline items. If an item is not overflowing, its value will be `null`. */
9
+ const UnderlineNavItemsRegistry = createDescendantRegistry();
10
+ const UnderlineNavItem = /*#__PURE__*/forwardRef((allProps, forwardedRef) => {
21
11
  const {
22
- setChildrenWidth,
23
- setNoIconChildrenWidth,
24
- loadingCounters,
25
- iconsVisible
12
+ as: Component = 'a',
13
+ href = '#',
14
+ children,
15
+ counter,
16
+ onSelect,
17
+ 'aria-current': ariaCurrent,
18
+ icon: Icon,
19
+ leadingVisual,
20
+ ...props
21
+ } = allProps;
22
+ const ref = useRef(null);
23
+ const {
24
+ loadingCounters
26
25
  } = useContext(UnderlineNavContext);
27
- useIsomorphicLayoutEffect(() => {
28
- if (ref.current) {
29
- const domRect = ref.current.getBoundingClientRect();
30
- const icon = Array.from(ref.current.children).find(child => child.getAttribute('data-component') === 'icon');
31
- const content = Array.from(ref.current.children).find(child => child.getAttribute('data-component') === 'text');
32
- const text = content.textContent;
33
- const iconWidthWithMargin = icon ? icon.getBoundingClientRect().width + Number(getComputedStyle(icon).marginRight.slice(0, -2)) + Number(getComputedStyle(icon).marginLeft.slice(0, -2)) : 0;
34
- setChildrenWidth({
35
- text,
36
- width: domRect.width
37
- });
38
- setNoIconChildrenWidth({
39
- text,
40
- width: domRect.width - iconWidthWithMargin
41
- });
42
- }
43
- }, [ref, setChildrenWidth, setNoIconChildrenWidth]);
26
+ const isOverflowing = useSyncExternalStore(useCallback(onChange => {
27
+ const observer = new IntersectionObserver(() => onChange(), {
28
+ threshold: 1
29
+ });
30
+ if (ref.current) observer.observe(ref.current);
31
+ return () => observer.disconnect();
32
+ }, [ref]),
33
+ // Note: the IntersectionObserver is just being used as a trigger to re-check
34
+ // `offsetTop > 0`; this is fast and simpler than checking visibility from
35
+ // the observed entry. When an item wraps, it will move to the next row which
36
+ // increases its `offsetTop`
37
+ () => ref.current ? ref.current.offsetTop > 0 : false, () => false);
38
+ UnderlineNavItemsRegistry.useRegisterDescendant(isOverflowing ? allProps : null);
44
39
  const keyDownHandler = React.useCallback(event => {
45
40
  if ((event.key === ' ' || event.key === 'Enter') && !event.defaultPrevented && typeof onSelect === 'function') {
46
41
  onSelect(event);
@@ -53,8 +48,10 @@ const UnderlineNavItem = /*#__PURE__*/forwardRef(({
53
48
  }, [onSelect]);
54
49
  return /*#__PURE__*/jsx("li", {
55
50
  className: classes.UnderlineNavItem,
51
+ ref: ref,
52
+ "aria-hidden": isOverflowing ? true : allProps['aria-hidden'],
56
53
  children: /*#__PURE__*/jsx(UnderlineItem, {
57
- ref: ref,
54
+ ref: forwardedRef,
58
55
  as: Component,
59
56
  href: href,
60
57
  "aria-current": ariaCurrent,
@@ -63,12 +60,12 @@ const UnderlineNavItem = /*#__PURE__*/forwardRef(({
63
60
  counter: counter,
64
61
  icon: leadingVisual !== null && leadingVisual !== void 0 ? leadingVisual : Icon,
65
62
  loadingCounters: loadingCounters,
66
- iconsVisible: iconsVisible,
67
63
  ...props,
64
+ tabIndex: isOverflowing ? -1 : allProps.tabIndex,
68
65
  children: children
69
66
  })
70
67
  });
71
68
  });
72
69
  UnderlineNavItem.displayName = 'UnderlineNavItem';
73
70
 
74
- export { UnderlineNavItem };
71
+ export { UnderlineNavItem, UnderlineNavItemsRegistry };
@@ -1,4 +1,4 @@
1
- import './UnderlineNavItem-b65e8fd3.css';
1
+ import './UnderlineNavItem-402cd41c.css';
2
2
 
3
3
  var classes = {"UnderlineNavItem":"prc-UnderlineNav-UnderlineNavItem-syRjR"};
4
4
 
@@ -1,3 +1,5 @@
1
1
  import React from 'react';
2
+ import type { UnderlineNavItemProps } from './UnderlineNavItem';
2
3
  export declare const getValidChildren: (children: React.ReactNode) => React.ReactElement<any>[];
4
+ export declare const isCurrent: (props: UnderlineNavItemProps) => boolean;
3
5
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,eAAO,MAAM,gBAAgB,GAAI,UAAU,KAAK,CAAC,SAAS,KAEgC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,EAChH,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oBAAoB,CAAA;AAE7D,eAAO,MAAM,gBAAgB,GAAI,UAAU,KAAK,CAAC,SAAS,KAEgC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,EAChH,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,OAAO,qBAAqB,YACuD,CAAA"}
@@ -4,5 +4,6 @@ const getValidChildren = children => {
4
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
5
  return React.Children.toArray(children).filter(child => /*#__PURE__*/React.isValidElement(child));
6
6
  };
7
+ const isCurrent = props => props['aria-current'] !== undefined && props['aria-current'] !== false && props['aria-current'] !== 'false';
7
8
 
8
- export { getValidChildren };
9
+ export { getValidChildren, isCurrent };
@@ -0,0 +1,2 @@
1
+ .prc-UnderlinePanels-StyledUnderlineWrapper-aiLna{overflow-x:auto;overflow-y:hidden;width:100%;-webkit-overflow-scrolling:auto}
2
+ /*# sourceMappingURL=UnderlinePanels-162f9aed.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/experimental/UnderlinePanels/UnderlinePanels.module.css.js"],"names":[],"mappings":"AAAA,kDAEE,eAAgB,CAChB,iBAAkB,CAFlB,UAAW,CAGX,+BACF","file":"UnderlinePanels-162f9aed.css","sourcesContent":[".StyledUnderlineWrapper {\n width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: auto;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import './UnderlinePanels-e4b325b9.css';
1
+ import './UnderlinePanels-162f9aed.css';
2
2
 
3
3
  var classes = {"StyledUnderlineWrapper":"prc-UnderlinePanels-StyledUnderlineWrapper-aiLna"};
4
4
 
@@ -0,0 +1,2 @@
1
+ .prc-components-UnderlineWrapper-eT-Yj{align-items:flex-start;box-shadow:inset 0 -1px var(--borderColor-muted,#d1d9e0b3);display:flex;justify-content:flex-start;min-height:var(--control-xlarge-size,3rem);padding-top:var(--base-size-8,.5rem);padding-inline:var(--stack-padding-normal,1rem)}.prc-components-UnderlineWrapper-eT-Yj[data-variant=flush]{padding-inline:unset}.prc-components-UnderlineWrapper-eT-Yj[data-hide-icons=true] [data-component=icon]{display:none}.prc-components-UnderlineWrapper-eT-Yj[data-overflow-mode=wrap]{max-height:var(--control-xlarge-size,3rem);overflow:hidden}.prc-components-UnderlineWrapper-eT-Yj[data-overflow-mode=wrap] .prc-components-UnderlineItemList-xKlKC{flex-wrap:wrap;overflow:hidden}.prc-components-UnderlineItemList-xKlKC{display:flex;gap:var(--stack-gap-condensed,.5rem);list-style:none;margin:0;padding:0;white-space:nowrap}.prc-components-UnderlineItem-7fP-n,.prc-components-UnderlineItemList-xKlKC{align-items:center;position:relative}.prc-components-UnderlineItem-7fP-n{appearance:none;background-color:transparent;border:0;border-radius:var(--borderRadius-medium,.375rem);color:var(--fgColor-default,#1f2328);cursor:pointer;display:inline-flex;font:inherit;font-size:var(--text-body-size-medium,.875rem);height:32px;line-height:var(--text-body-lineHeight-medium,1.4285);margin-bottom:var(--base-size-8,.5rem);max-width:100%;padding-block:var(--base-size-6,.375rem);padding-inline:var(--base-size-8,.5rem);text-align:center;-webkit-text-decoration:none;text-decoration:none}@media (hover:hover){.prc-components-UnderlineItem-7fP-n:hover{background-color:var(--bgColor-neutral-muted,#818b981f);-webkit-text-decoration:none;text-decoration:none;transition:background-color .12s ease-out}}.prc-components-UnderlineItem-7fP-n:focus{box-shadow:inset 0 0 0 2px var(--fgColor-accent,#0969da);outline:2px solid transparent}.prc-components-UnderlineItem-7fP-n:focus:not(:focus-visible){box-shadow:none}.prc-components-UnderlineItem-7fP-n:focus-visible{box-shadow:inset 0 0 0 2px var(--fgColor-accent,#0969da);outline:2px solid transparent}.prc-components-UnderlineItem-7fP-n [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden;white-space:nowrap}.prc-components-UnderlineItem-7fP-n [data-component=icon]{align-items:center;color:var(--fgColor-muted,#59636e);display:inline-flex;margin-inline-end:var(--base-size-8,.5rem)}.prc-components-UnderlineItem-7fP-n [data-component=text]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.prc-components-UnderlineItem-7fP-n [data-component=counter]{align-items:center;display:flex;margin-inline-start:var(--base-size-8,.5rem)}.prc-components-UnderlineItem-7fP-n:after{background-color:transparent;content:"";height:2px;inset:auto 0 0;margin-bottom:calc(var(--base-size-8,.5rem)*-1);pointer-events:none;position:absolute}.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]) [data-component=text],.prc-components-UnderlineItem-7fP-n[aria-selected=true] [data-component=text]{font-weight:var(--base-text-weight-semibold,600)}.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]):after,.prc-components-UnderlineItem-7fP-n[aria-selected=true]:after{background-color:var(--underlineNav-borderColor-active,var(--color-primer-border-active,#fd8c73))}@media (forced-colors:active){.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]):after,.prc-components-UnderlineItem-7fP-n[aria-selected=true]:after{background-color:LinkText}}.prc-components-LoadingCounter-dBuLy{animation:prc-components-loadingCounterKeyFrames-8tMlf 1.2s ease-in-out infinite alternate;background-color:var(--bgColor-neutral-muted,#818b981f);border-color:var(--borderColor-default,#d1d9e0);border-radius:20px;display:inline-block;height:1rem;width:1.5rem}@keyframes prc-components-loadingCounterKeyFrames-8tMlf{0%{opacity:1}to{opacity:.2}}
2
+ /*# sourceMappingURL=UnderlineTabbedInterface-1745a3d6.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/internal/components/UnderlineTabbedInterface.module.css.js"],"names":[],"mappings":"AAAA,uCAME,sBAAuB,CAOvB,0DAAiD,CAZjD,YAAa,CAIb,0BAA2B,CAI3B,0CAAsC,CAPtC,oCAA+B,CAE/B,+CA8BF,CAnBE,2DAEE,oBACF,CAEA,mFACE,YACF,CAEA,gEAGE,0CAAsC,CADtC,eAOF,CAJE,wGACE,cAAe,CACf,eACF,CAIJ,wCAEE,YAAa,CAMb,oCAA+B,CAF/B,eAAgB,CAFhB,QAAS,CADT,SAAU,CAEV,kBAIF,CAEA,4EAJE,kBAAmB,CANnB,iBAyCF,CA/BA,oCAmBE,eAAgB,CARhB,4BAA6B,CAC7B,QAAS,CACT,gDAAyC,CANzC,oCAA6B,CAG7B,cAAe,CAPf,mBAAoB,CACpB,YAAa,CACb,8CAAuC,CAWvC,WAAY,CAVZ,qDAAuD,CASvD,sCAAiC,CADjC,cAAe,CAOf,wCAAiC,CADjC,uCAAkC,CAZlC,iBAAkB,CAClB,4BAAqB,CAArB,oBAsBF,CAPE,qBACE,0CAEE,uDAA8C,CAD9C,4BAAqB,CAArB,oBAAqB,CAErB,yCACF,CACF,CAGF,0CAGE,wDAAiD,CAFjD,6BAQF,CAHE,8DACE,eACF,CAGF,kDAGE,wDAAiD,CAFjD,6BAGF,CAGA,0DAME,0BAA2B,CAL3B,aAAc,CAEd,gDAA6C,CAD7C,QAAS,CAGT,iBAAkB,CADlB,kBAGF,CAEA,0DAGE,kBAAmB,CADnB,kCAA2B,CAD3B,mBAAoB,CAGpB,0CACF,CAGA,0DACE,eAAgB,CAChB,sBAAuB,CACvB,kBACF,CAEA,6DAGE,kBAAmB,CADnB,YAAa,CADb,4CAGF,CAEA,0CAOE,4BAA6B,CAD7B,UAAW,CAFX,UAAW,CAFX,cAAe,CACf,+CAA4C,CAE5C,mBAAoB,CAJpB,iBAOF,CAEA,gLAEE,gDACF,CAEA,gJAGE,iGAMF,CAJE,8BALF,gJAOI,yBAEJ,CADE,CAGF,qCASE,0FAAsE,CAJtE,uDAA8C,CAC9C,+CAAwC,CAExC,kBAAmB,CAPnB,oBAAqB,CAErB,WAAY,CADZ,YAQF,CAEA,wDACE,GACE,SACF,CAEA,GACE,UACF,CACF","file":"UnderlineTabbedInterface-1745a3d6.css","sourcesContent":[".UnderlineWrapper {\n display: flex;\n padding-top: var(--base-size-8);\n /* stylelint-disable-next-line primer/spacing */\n padding-inline: var(--stack-padding-normal);\n justify-content: flex-start;\n align-items: flex-start;\n\n /* make space for the underline */\n min-height: var(--control-xlarge-size);\n\n /* using a box-shadow instead of a border to accommodate 'overflow-y: hidden' on UnderlinePanels */\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 -1px var(--borderColor-muted);\n\n &[data-variant='flush'] {\n /* stylelint-disable-next-line primer/spacing */\n padding-inline: unset;\n }\n\n &[data-hide-icons='true'] [data-component='icon'] {\n display: none;\n }\n\n &[data-overflow-mode='wrap'] {\n /* Wrap items onto hidden next lines */\n overflow: hidden;\n max-height: var(--control-xlarge-size);\n\n .UnderlineItemList {\n flex-wrap: wrap;\n overflow: hidden;\n }\n }\n}\n\n.UnderlineItemList {\n position: relative;\n display: flex;\n padding: 0;\n margin: 0;\n white-space: nowrap;\n list-style: none;\n align-items: center;\n gap: var(--stack-gap-condensed);\n}\n\n.UnderlineItem {\n /* underline tab specific styles */\n position: relative;\n display: inline-flex;\n font: inherit;\n font-size: var(--text-body-size-medium);\n line-height: var(--text-body-lineHeight-medium, 1.4285);\n color: var(--fgColor-default);\n text-align: center;\n text-decoration: none;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--borderRadius-medium);\n max-width: 100%;\n margin-bottom: var(--base-size-8);\n height: 32px;\n\n /* button resets */\n appearance: none;\n padding-inline: var(--base-size-8);\n padding-block: var(--base-size-6);\n align-items: center;\n\n @media (hover: hover) {\n &:hover {\n text-decoration: none;\n background-color: var(--bgColor-neutral-muted);\n transition: background-color 0.12s ease-out;\n }\n }\n}\n\n.UnderlineItem:focus {\n outline: 2px solid transparent;\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 0 0 2px var(--fgColor-accent);\n\n /* where focus-visible is supported, remove the focus box-shadow */\n &:not(:focus-visible) {\n box-shadow: none;\n }\n}\n\n.UnderlineItem:focus-visible {\n outline: 2px solid transparent;\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 0 0 2px var(--fgColor-accent);\n}\n\n/* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n.UnderlineItem [data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n white-space: nowrap;\n visibility: hidden;\n content: attr(data-content);\n}\n\n.UnderlineItem [data-component='icon'] {\n display: inline-flex;\n color: var(--fgColor-muted);\n align-items: center;\n margin-inline-end: var(--base-size-8);\n}\n\n/* Truncate items if necessary (should only ever apply to the last item after everything else overflows) */\n.UnderlineItem [data-component='text'] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.UnderlineItem [data-component='counter'] {\n margin-inline-start: var(--base-size-8);\n display: flex;\n align-items: center;\n}\n\n.UnderlineItem::after {\n position: absolute;\n inset: auto 0 0;\n margin-bottom: calc(-1 * var(--base-size-8));\n height: 2px;\n pointer-events: none;\n content: '';\n background-color: transparent;\n}\n\n.UnderlineItem[aria-current]:not([aria-current='false']) [data-component='text'],\n.UnderlineItem[aria-selected='true'] [data-component='text'] {\n font-weight: var(--base-text-weight-semibold);\n}\n\n.UnderlineItem[aria-current]:not([aria-current='false'])::after,\n.UnderlineItem[aria-selected='true']::after {\n /* stylelint-disable-next-line primer/colors */\n background-color: var(--underlineNav-borderColor-active, var(--color-primer-border-active, #fd8c73));\n\n @media (forced-colors: active) {\n /* Support for Window Force Color Mode https://learn.microsoft.com/en-us/fluent-ui/web-components/design-system/high-contrast */\n background-color: LinkText;\n }\n}\n\n.LoadingCounter {\n display: inline-block;\n width: 1.5rem;\n height: 1rem;\n /* 16px */\n background-color: var(--bgColor-neutral-muted);\n border-color: var(--borderColor-default);\n /* stylelint-disable-next-line primer/borders */\n border-radius: 20px;\n animation: loadingCounterKeyFrames 1.2s ease-in-out infinite alternate;\n}\n\n@keyframes loadingCounterKeyFrames {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0.2;\n }\n}\n"]}
@@ -15,7 +15,6 @@ export declare const LoadingCounter: () => React.JSX.Element;
15
15
  export type UnderlineItemProps<As extends React.ElementType> = {
16
16
  as?: As | 'a' | 'button';
17
17
  className?: string;
18
- iconsVisible?: boolean;
19
18
  loadingCounters?: boolean;
20
19
  counter?: number | string;
21
20
  icon?: FC<IconProps> | React.ReactElement<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"UnderlineTabbedInterface.d.ts","sourceRoot":"","sources":["../../../src/internal/components/UnderlineTabbedInterface.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAgC,KAAK,EAAE,EAA0B,KAAK,WAAW,EAAC,MAAM,OAAO,CAAA;AAEtG,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAErD,OAAO,KAAK,EAAC,mBAAmB,IAAI,8BAA8B,EAAC,MAAM,yBAAyB,CAAA;AAMlG,eAAO,MAAM,GAAG,IAAI,CAAA;AAgBpB,KAAK,qBAAqB,CAAC,EAAE,SAAS,KAAK,CAAC,WAAW,IAAI;IACzD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,EAAE,CAAA;IACP,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;CAC7B,CAAA;AAED,eAAO,MAAM,gBAAgB,EAWvB,8BAA8B,CAAC,WAAW,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAA;AAErF,eAAO,MAAM,iBAAiB,EAMxB,8BAA8B,CAAC,IAAI,CAAC,CAAA;AAE1C,eAAO,MAAM,cAAc,yBAE1B,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,EAAE,SAAS,KAAK,CAAC,WAAW,IAAI;IAC7D,EAAE,CAAC,EAAE,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAEzB,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAC9C,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;CACzB,GAAG,KAAK,CAAC,wBAAwB,CAAC,EAAE,SAAS,GAAG,GAAG,GAAG,GAAG,EAAE,SAAS,QAAQ,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAA;AAE9F,eAAO,MAAM,aAAa,EAwBpB,8BAA8B,CAAC,WAAW,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"UnderlineTabbedInterface.d.ts","sourceRoot":"","sources":["../../../src/internal/components/UnderlineTabbedInterface.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAgC,KAAK,EAAE,EAAE,KAAK,WAAW,EAAC,MAAM,OAAO,CAAA;AAE9E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAErD,OAAO,KAAK,EAAC,mBAAmB,IAAI,8BAA8B,EAAC,MAAM,yBAAyB,CAAA;AAMlG,eAAO,MAAM,GAAG,IAAI,CAAA;AAgBpB,KAAK,qBAAqB,CAAC,EAAE,SAAS,KAAK,CAAC,WAAW,IAAI;IACzD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,EAAE,CAAA;IACP,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;CAC7B,CAAA;AAED,eAAO,MAAM,gBAAgB,EAYvB,8BAA8B,CAAC,WAAW,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAA;AAErF,eAAO,MAAM,iBAAiB,EAMxB,8BAA8B,CAAC,IAAI,CAAC,CAAA;AAE1C,eAAO,MAAM,cAAc,yBAE1B,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,EAAE,SAAS,KAAK,CAAC,WAAW,IAAI;IAC7D,EAAE,CAAC,EAAE,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAEzB,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAC9C,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;CACzB,GAAG,KAAK,CAAC,wBAAwB,CAAC,EAAE,SAAS,GAAG,GAAG,GAAG,GAAG,EAAE,SAAS,QAAQ,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAA;AAE9F,eAAO,MAAM,aAAa,EAwBpB,8BAA8B,CAAC,WAAW,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAA"}
@@ -6,8 +6,6 @@ import { clsx } from 'clsx';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
7
7
  import CounterLabel from '../../CounterLabel/CounterLabel.js';
8
8
 
9
- const GAP = 8;
10
-
11
9
  // Helper to extract direct text content from children for the data-content attribute.
12
10
  // This is used by CSS to reserve space for bold text (preventing layout shift).
13
11
  // Only extracts strings/numbers, not text from nested React elements (e.g., Popovers).
@@ -75,37 +73,50 @@ const UnderlineWrapper = /*#__PURE__*/forwardRef((props, ref) => {
75
73
  return t3;
76
74
  });
77
75
  const UnderlineItemList = /*#__PURE__*/forwardRef((t0, forwardedRef) => {
78
- const $ = c(7);
76
+ const $ = c(11);
79
77
  let children;
78
+ let className;
80
79
  let rest;
81
80
  if ($[0] !== t0) {
82
81
  ({
83
82
  children,
83
+ className,
84
84
  ...rest
85
85
  } = t0);
86
86
  $[0] = t0;
87
87
  $[1] = children;
88
- $[2] = rest;
88
+ $[2] = className;
89
+ $[3] = rest;
89
90
  } else {
90
91
  children = $[1];
91
- rest = $[2];
92
+ className = $[2];
93
+ rest = $[3];
92
94
  }
93
95
  let t1;
94
- if ($[3] !== children || $[4] !== forwardedRef || $[5] !== rest) {
95
- t1 = /*#__PURE__*/jsx("ul", {
96
- className: classes.UnderlineItemList,
96
+ if ($[4] !== className) {
97
+ t1 = clsx(className, classes.UnderlineItemList);
98
+ $[4] = className;
99
+ $[5] = t1;
100
+ } else {
101
+ t1 = $[5];
102
+ }
103
+ let t2;
104
+ if ($[6] !== children || $[7] !== forwardedRef || $[8] !== rest || $[9] !== t1) {
105
+ t2 = /*#__PURE__*/jsx("ul", {
106
+ className: t1,
97
107
  ref: forwardedRef,
98
108
  ...rest,
99
109
  children: children
100
110
  });
101
- $[3] = children;
102
- $[4] = forwardedRef;
103
- $[5] = rest;
104
- $[6] = t1;
111
+ $[6] = children;
112
+ $[7] = forwardedRef;
113
+ $[8] = rest;
114
+ $[9] = t1;
115
+ $[10] = t2;
105
116
  } else {
106
- t1 = $[6];
117
+ t2 = $[10];
107
118
  }
108
- return t1;
119
+ return t2;
109
120
  });
110
121
  const LoadingCounter = () => {
111
122
  const $ = c(1);
@@ -121,12 +132,11 @@ const LoadingCounter = () => {
121
132
  return t0;
122
133
  };
123
134
  const UnderlineItem = /*#__PURE__*/React.forwardRef((props, ref) => {
124
- const $ = c(30);
135
+ const $ = c(28);
125
136
  let Icon;
126
137
  let children;
127
138
  let className;
128
139
  let counter;
129
- let iconsVisible;
130
140
  let loadingCounters;
131
141
  let rest;
132
142
  let t0;
@@ -136,7 +146,6 @@ const UnderlineItem = /*#__PURE__*/React.forwardRef((props, ref) => {
136
146
  children,
137
147
  counter,
138
148
  icon: Icon,
139
- iconsVisible,
140
149
  loadingCounters,
141
150
  className,
142
151
  ...rest
@@ -146,65 +155,62 @@ const UnderlineItem = /*#__PURE__*/React.forwardRef((props, ref) => {
146
155
  $[2] = children;
147
156
  $[3] = className;
148
157
  $[4] = counter;
149
- $[5] = iconsVisible;
150
- $[6] = loadingCounters;
151
- $[7] = rest;
152
- $[8] = t0;
158
+ $[5] = loadingCounters;
159
+ $[6] = rest;
160
+ $[7] = t0;
153
161
  } else {
154
162
  Icon = $[1];
155
163
  children = $[2];
156
164
  className = $[3];
157
165
  counter = $[4];
158
- iconsVisible = $[5];
159
- loadingCounters = $[6];
160
- rest = $[7];
161
- t0 = $[8];
166
+ loadingCounters = $[5];
167
+ rest = $[6];
168
+ t0 = $[7];
162
169
  }
163
170
  const Component = t0 === undefined ? "a" : t0;
164
171
  let t1;
165
- if ($[9] !== children) {
172
+ if ($[8] !== children) {
166
173
  t1 = getTextContent(children);
167
- $[9] = children;
168
- $[10] = t1;
174
+ $[8] = children;
175
+ $[9] = t1;
169
176
  } else {
170
- t1 = $[10];
177
+ t1 = $[9];
171
178
  }
172
179
  const textContent = t1;
173
180
  let t2;
174
- if ($[11] !== className) {
181
+ if ($[10] !== className) {
175
182
  t2 = clsx(classes.UnderlineItem, className);
176
- $[11] = className;
177
- $[12] = t2;
183
+ $[10] = className;
184
+ $[11] = t2;
178
185
  } else {
179
- t2 = $[12];
186
+ t2 = $[11];
180
187
  }
181
188
  let t3;
182
- if ($[13] !== Icon || $[14] !== iconsVisible) {
183
- t3 = iconsVisible && Icon && /*#__PURE__*/jsx("span", {
189
+ if ($[12] !== Icon) {
190
+ t3 = Icon && /*#__PURE__*/jsx("span", {
184
191
  "data-component": "icon",
185
192
  children: isElement(Icon) ? Icon : /*#__PURE__*/jsx(Icon, {})
186
193
  });
187
- $[13] = Icon;
188
- $[14] = iconsVisible;
189
- $[15] = t3;
194
+ $[12] = Icon;
195
+ $[13] = t3;
190
196
  } else {
191
- t3 = $[15];
197
+ t3 = $[13];
192
198
  }
193
199
  let t4;
194
- if ($[16] !== children || $[17] !== textContent) {
200
+ if ($[14] !== children || $[15] !== textContent) {
195
201
  t4 = children && /*#__PURE__*/jsx("span", {
196
202
  "data-component": "text",
197
203
  "data-content": textContent || undefined,
198
204
  children: children
199
205
  });
200
- $[16] = children;
201
- $[17] = textContent;
202
- $[18] = t4;
206
+ $[14] = children;
207
+ $[15] = textContent;
208
+ $[16] = t4;
203
209
  } else {
204
- t4 = $[18];
210
+ t4 = $[16];
205
211
  }
206
212
  let t5;
207
- if ($[19] !== counter || $[20] !== loadingCounters) {
213
+ if ($[17] !== counter || $[18] !== loadingCounters) {
208
214
  t5 = counter !== undefined ? loadingCounters ? /*#__PURE__*/jsx("span", {
209
215
  "data-component": "counter",
210
216
  children: /*#__PURE__*/jsx(LoadingCounter, {})
@@ -214,32 +220,32 @@ const UnderlineItem = /*#__PURE__*/React.forwardRef((props, ref) => {
214
220
  children: counter
215
221
  })
216
222
  }) : null;
217
- $[19] = counter;
218
- $[20] = loadingCounters;
219
- $[21] = t5;
223
+ $[17] = counter;
224
+ $[18] = loadingCounters;
225
+ $[19] = t5;
220
226
  } else {
221
- t5 = $[21];
227
+ t5 = $[19];
222
228
  }
223
229
  let t6;
224
- if ($[22] !== Component || $[23] !== ref || $[24] !== rest || $[25] !== t2 || $[26] !== t3 || $[27] !== t4 || $[28] !== t5) {
230
+ if ($[20] !== Component || $[21] !== ref || $[22] !== rest || $[23] !== t2 || $[24] !== t3 || $[25] !== t4 || $[26] !== t5) {
225
231
  t6 = /*#__PURE__*/jsxs(Component, {
226
232
  ...rest,
227
233
  ref: ref,
228
234
  className: t2,
229
235
  children: [t3, t4, t5]
230
236
  });
231
- $[22] = Component;
232
- $[23] = ref;
233
- $[24] = rest;
234
- $[25] = t2;
235
- $[26] = t3;
236
- $[27] = t4;
237
- $[28] = t5;
238
- $[29] = t6;
237
+ $[20] = Component;
238
+ $[21] = ref;
239
+ $[22] = rest;
240
+ $[23] = t2;
241
+ $[24] = t3;
242
+ $[25] = t4;
243
+ $[26] = t5;
244
+ $[27] = t6;
239
245
  } else {
240
- t6 = $[29];
246
+ t6 = $[27];
241
247
  }
242
248
  return t6;
243
249
  });
244
250
 
245
- export { GAP, LoadingCounter, UnderlineItem, UnderlineItemList, UnderlineWrapper };
251
+ export { LoadingCounter, UnderlineItem, UnderlineItemList, UnderlineWrapper };
@@ -1,4 +1,4 @@
1
- import './UnderlineTabbedInterface-4197ee28.css';
1
+ import './UnderlineTabbedInterface-1745a3d6.css';
2
2
 
3
3
  var classes = {"UnderlineWrapper":"prc-components-UnderlineWrapper-eT-Yj","UnderlineItemList":"prc-components-UnderlineItemList-xKlKC","UnderlineItem":"prc-components-UnderlineItem-7fP-n","LoadingCounter":"prc-components-LoadingCounter-dBuLy","loadingCounterKeyFrames":"prc-components-loadingCounterKeyFrames-8tMlf"};
4
4
 
@@ -8956,11 +8956,11 @@
8956
8956
  },
8957
8957
  {
8958
8958
  "id": "components-underlinenav-features--overflow-template",
8959
- "code": "({ initialSelectedIndex = 1 }: { initialSelectedIndex?: number }) => {\n const [selectedIndex, setSelectedIndex] = React.useState<number | null>(\n initialSelectedIndex,\n )\n return (\n <UnderlineNav\n aria-label=\"Repository\"\n // @ts-ignore UnderlineNav does not take selectionVariant prop, but we need to pass it to the underlying ActionList so it doesn't show Selections.\n selectionVariant={undefined}\n >\n {items.map((item, index) => (\n <UnderlineNav.Item\n key={item.navigation}\n leadingVisual={item.icon}\n aria-current={index === selectedIndex ? 'page' : undefined}\n // Set so that navigation in interaction tests does not cause the\n // page to load the storybook iframe URL and instead keeps the test in\n // the local preview\n target=\"_self\"\n onSelect={(event) => {\n event.preventDefault()\n setSelectedIndex(index)\n }}\n counter={item.counter}\n href={item.href}\n >\n {item.navigation}\n </UnderlineNav.Item>\n ))}\n </UnderlineNav>\n )\n}"
8959
+ "code": "({ initialSelectedIndex = 1 }: { initialSelectedIndex?: number }) => {\n const [selectedIndex, setSelectedIndex] = React.useState<number | null>(\n initialSelectedIndex,\n )\n return (\n <UnderlineNav aria-label=\"Repository\">\n {items.map((item, index) => (\n <UnderlineNav.Item\n key={item.navigation}\n leadingVisual={item.icon}\n aria-current={index === selectedIndex ? 'page' : undefined}\n // Set so that navigation in interaction tests does not cause the\n // page to load the storybook iframe URL and instead keeps the test in\n // the local preview\n target=\"_self\"\n onSelect={(event) => {\n event.preventDefault()\n setSelectedIndex(index)\n }}\n counter={item.counter}\n href={item.href}\n >\n {item.navigation}\n </UnderlineNav.Item>\n ))}\n </UnderlineNav>\n )\n}"
8960
8960
  },
8961
8961
  {
8962
8962
  "id": "components-underlinenav-features--overflow-on-narrow-screen",
8963
- "code": "() => {\n return <OverflowTemplate initialSelectedIndex={1} />\n}"
8963
+ "code": "() => {\n return <OverflowTemplate initialSelectedIndex={items.length - 1} />\n}"
8964
8964
  },
8965
8965
  {
8966
8966
  "id": "components-underlinenav-features--counters-loading-state",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primer/react",
3
3
  "type": "module",
4
- "version": "0.0.0-20260619134534",
4
+ "version": "0.0.0-20260619191426",
5
5
  "description": "An implementation of GitHub's Primer Design System using React",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -1,2 +0,0 @@
1
- .prc-UnderlineNav-MenuItemContent-3J7gB{align-items:center;display:flex;justify-content:space-between}.prc-UnderlineNav-MoreButton-Y8soj{background:transparent;border:0;box-shadow:none;font-weight:var(--base-text-weight-normal,400);margin:0;padding:var(--base-size-4,.25rem) var(--base-size-8,.5rem)}.prc-UnderlineNav-MoreButton-Y8soj>[data-component=trailingVisual]{margin-left:0}
2
- /*# sourceMappingURL=UnderlineNav-4344d9b0.css.map */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/UnderlineNav/UnderlineNav.module.css.js"],"names":[],"mappings":"AAAA,wCAEE,kBAAmB,CADnB,YAAa,CAEb,6BACF,CAGA,mCAGE,sBAAuB,CADvB,QAAS,CAGT,eAAgB,CADhB,8CAA2C,CAH3C,QAAS,CAQT,0DAKF,CAHE,mEACE,aACF","file":"UnderlineNav-4344d9b0.css","sourcesContent":[".MenuItemContent {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n/* More button styles migrated from styles.ts (was moreBtnStyles) */\n.MoreButton {\n margin: 0; /* reset Safari extra margin */\n border: 0;\n background: transparent;\n font-weight: var(--base-text-weight-normal);\n box-shadow: none;\n padding-top: var(--base-size-4);\n padding-bottom: var(--base-size-4);\n padding-left: var(--base-size-8);\n padding-right: var(--base-size-8);\n\n & > [data-component='trailingVisual'] {\n margin-left: 0;\n }\n}\n"]}
@@ -1,2 +0,0 @@
1
- .prc-UnderlineNav-UnderlineNavItem-syRjR{align-items:center;display:flex;flex-direction:column}
2
- /*# sourceMappingURL=UnderlineNavItem-b65e8fd3.css.map */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/UnderlineNav/UnderlineNavItem.module.css.js"],"names":[],"mappings":"AAAA,yCAGE,kBAAmB,CAFnB,YAAa,CACb,qBAEF","file":"UnderlineNavItem-b65e8fd3.css","sourcesContent":[".UnderlineNavItem {\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n"]}
@@ -1,16 +0,0 @@
1
- export declare const dividerStyles: {
2
- display: string;
3
- borderLeft: string;
4
- width: string;
5
- borderLeftColor: string;
6
- marginRight: string;
7
- height: string;
8
- };
9
- export declare const menuItemStyles: {
10
- '& > span': {
11
- display: string;
12
- };
13
- textDecoration: string;
14
- };
15
- export declare const baseMenuMinWidth = 192;
16
- //# sourceMappingURL=styles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/UnderlineNav/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;CAOzB,CAAA;AAED,eAAO,MAAM,cAAc;;;;;CAO1B,CAAA;AAED,eAAO,MAAM,gBAAgB,MAAM,CAAA"}
@@ -1,19 +0,0 @@
1
- const dividerStyles = {
2
- display: 'inline-block',
3
- borderLeft: '1px solid',
4
- width: '1px',
5
- borderLeftColor: 'var(--borderColor-muted)',
6
- marginRight: 'var(--base-size-4)',
7
- height: '24px' // The height of the divider - reference from Figma
8
- };
9
- const menuItemStyles = {
10
- // This is needed to hide the selected check icon on the menu item. https://github.com/primer/react/tree/main/packages/react/src/ActionList/Selection.tsx#L32
11
- '& > span': {
12
- display: 'none'
13
- },
14
- // To reset the style when the menu items are rendered as react router links
15
- textDecoration: 'none'
16
- };
17
- const baseMenuMinWidth = 192;
18
-
19
- export { baseMenuMinWidth, dividerStyles, menuItemStyles };
@@ -1,2 +0,0 @@
1
- .prc-UnderlinePanels-StyledUnderlineWrapper-aiLna{overflow-x:auto;overflow-y:hidden;width:100%;-webkit-overflow-scrolling:auto}.prc-UnderlinePanels-StyledUnderlineWrapper-aiLna[data-icons-visible=false] [data-component=icon]{display:none}
2
- /*# sourceMappingURL=UnderlinePanels-e4b325b9.css.map */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/experimental/UnderlinePanels/UnderlinePanels.module.css.js"],"names":[],"mappings":"AAAA,kDAEE,eAAgB,CAChB,iBAAkB,CAFlB,UAAW,CAGX,+BACF,CAEA,kGACE,YACF","file":"UnderlinePanels-e4b325b9.css","sourcesContent":[".StyledUnderlineWrapper {\n width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: auto;\n}\n\n.StyledUnderlineWrapper[data-icons-visible='false'] [data-component='icon'] {\n display: none;\n}\n"]}
@@ -1,2 +0,0 @@
1
- .prc-components-UnderlineWrapper-eT-Yj{align-items:center;box-shadow:inset 0 -1px var(--borderColor-muted,#d1d9e0b3);display:flex;justify-content:flex-start;min-height:var(--control-xlarge-size,48px);overflow:visible;padding-inline:var(--stack-padding-normal,1rem)}.prc-components-UnderlineWrapper-eT-Yj[data-overflow-measured=false]{overflow:hidden}.prc-components-UnderlineWrapper-eT-Yj[data-overflow-measured=true]{overflow:visible}.prc-components-UnderlineWrapper-eT-Yj[data-variant=flush]{padding-inline:unset}.prc-components-UnderlineItemList-xKlKC{display:flex;gap:8px;list-style:none;margin:0;padding:0;white-space:nowrap}.prc-components-UnderlineItem-7fP-n,.prc-components-UnderlineItemList-xKlKC{align-items:center;position:relative}.prc-components-UnderlineItem-7fP-n{appearance:none;background-color:transparent;border:0;border-radius:var(--borderRadius-medium,var(--borderRadius-small,.1875rem));color:var(--fgColor-default,#1f2328);cursor:pointer;display:inline-flex;font:inherit;font-size:var(--text-body-size-medium,.875rem);line-height:var(--text-body-lineHeight-medium,1.4285);padding-block:var(--base-size-6,.375rem);padding-inline:var(--base-size-8,.5rem);text-align:center;-webkit-text-decoration:none;text-decoration:none}@media (hover:hover){.prc-components-UnderlineItem-7fP-n:hover{background-color:var(--bgColor-neutral-muted,#818b981f);-webkit-text-decoration:none;text-decoration:none;transition:background-color .12s ease-out}}.prc-components-UnderlineItem-7fP-n:focus{box-shadow:inset 0 0 0 2px var(--fgColor-accent,#0969da);outline:2px solid transparent}.prc-components-UnderlineItem-7fP-n:focus:not(:focus-visible){box-shadow:none}.prc-components-UnderlineItem-7fP-n:focus-visible{box-shadow:inset 0 0 0 2px var(--fgColor-accent,#0969da);outline:2px solid transparent}.prc-components-UnderlineItem-7fP-n [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden;white-space:nowrap}.prc-components-UnderlineItem-7fP-n [data-component=icon]{align-items:center;color:var(--fgColor-muted,#59636e);display:inline-flex;margin-inline-end:var(--base-size-8,.5rem)}.prc-components-UnderlineItem-7fP-n [data-component=counter]{align-items:center;display:flex;margin-inline-start:var(--base-size-8,.5rem)}.prc-components-UnderlineItem-7fP-n:after{background-color:transparent;border-radius:0;bottom:calc(50% - var(--control-xlarge-size, var(--base-size-48,3rem))/2 - 1px);content:"";height:2px;pointer-events:none;position:absolute;right:50%;transform:translate(50%,-50%);width:100%}.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]) [data-component=text],.prc-components-UnderlineItem-7fP-n[aria-selected=true] [data-component=text]{font-weight:var(--base-text-weight-semibold,600)}.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]):after,.prc-components-UnderlineItem-7fP-n[aria-selected=true]:after{background-color:var(--underlineNav-borderColor-active,var(--color-primer-border-active,#fd8c73))}@media (forced-colors:active){.prc-components-UnderlineItem-7fP-n[aria-current]:not([aria-current=false]):after,.prc-components-UnderlineItem-7fP-n[aria-selected=true]:after{background-color:LinkText}}.prc-components-LoadingCounter-dBuLy{animation:prc-components-loadingCounterKeyFrames-8tMlf 1.2s ease-in-out infinite alternate;background-color:var(--bgColor-neutral-muted,#818b981f);border-color:var(--borderColor-default,#d1d9e0);border-radius:20px;display:inline-block;height:1rem;width:1.5rem}@keyframes prc-components-loadingCounterKeyFrames-8tMlf{0%{opacity:1}to{opacity:.2}}
2
- /*# sourceMappingURL=UnderlineTabbedInterface-4197ee28.css.map */
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/internal/components/UnderlineTabbedInterface.module.css.js"],"names":[],"mappings":"AAAA,uCAKE,kBAAmB,CAOnB,0DAAiD,CAXjD,YAAa,CAGb,0BAA2B,CAI3B,0CAA4C,CAO5C,gBAAiB,CAZjB,+CA0BF,CAZE,qEACE,eACF,CAEA,oEACE,gBACF,CAEA,2DAEE,oBACF,CAGF,wCAEE,YAAa,CAMb,OAAQ,CAFR,eAAgB,CAFhB,QAAS,CADT,SAAU,CAEV,kBAIF,CAEA,4EAJE,kBAAmB,CANnB,iBAsCF,CA5BA,oCAgBE,eAAgB,CALhB,4BAA6B,CAC7B,QAAS,CACT,2EAAoE,CANpE,oCAA6B,CAG7B,cAAe,CAPf,mBAAoB,CACpB,YAAa,CACb,8CAAuC,CACvC,qDAAuD,CAYvD,wCAAiC,CADjC,uCAAkC,CATlC,iBAAkB,CAClB,4BAAqB,CAArB,oBAmBF,CAPE,qBACE,0CAEE,uDAA8C,CAD9C,4BAAqB,CAArB,oBAAqB,CAErB,yCACF,CACF,CAGF,0CAGE,wDAAiD,CAFjD,6BAQF,CAHE,8DACE,eACF,CAGF,kDAGE,wDAAiD,CAFjD,6BAGF,CAGA,0DAME,0BAA2B,CAL3B,aAAc,CAEd,gDAA6C,CAD7C,QAAS,CAGT,iBAAkB,CADlB,kBAGF,CAEA,0DAGE,kBAAmB,CADnB,kCAA2B,CAD3B,mBAAoB,CAGpB,0CACF,CAEA,6DAGE,kBAAmB,CADnB,YAAa,CADb,4CAGF,CAEA,0CAaE,4BAA6B,CAC7B,eAAgB,CANhB,+EAAmF,CAInF,UAAW,CAFX,UAAW,CACX,mBAAoB,CAVpB,iBAAkB,CAClB,SAAU,CAaV,6BAA+B,CAN/B,UAOF,CAEA,gLAEE,gDACF,CAEA,gJAGE,iGAMF,CAJE,8BALF,gJAOI,yBAEJ,CADE,CAGF,qCASE,0FAAsE,CAJtE,uDAA8C,CAC9C,+CAAwC,CAExC,kBAAmB,CAPnB,oBAAqB,CAErB,WAAY,CADZ,YAQF,CAEA,wDACE,GACE,SACF,CAEA,GACE,UACF,CACF","file":"UnderlineTabbedInterface-4197ee28.css","sourcesContent":[".UnderlineWrapper {\n display: flex;\n /* stylelint-disable-next-line primer/spacing */\n padding-inline: var(--stack-padding-normal);\n justify-content: flex-start;\n align-items: center;\n\n /* make space for the underline */\n min-height: var(--control-xlarge-size, 48px);\n\n /* using a box-shadow instead of a border to accommodate 'overflow-y: hidden' on UnderlinePanels */\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 -1px var(--borderColor-muted);\n\n /* Hide overflow until calculation is complete to prevent CLS */\n overflow: visible;\n\n &[data-overflow-measured='false'] {\n overflow: hidden;\n }\n\n &[data-overflow-measured='true'] {\n overflow: visible;\n }\n\n &[data-variant='flush'] {\n /* stylelint-disable-next-line primer/spacing */\n padding-inline: unset;\n }\n}\n\n.UnderlineItemList {\n position: relative;\n display: flex;\n padding: 0;\n margin: 0;\n white-space: nowrap;\n list-style: none;\n align-items: center;\n gap: 8px;\n}\n\n.UnderlineItem {\n /* underline tab specific styles */\n position: relative;\n display: inline-flex;\n font: inherit;\n font-size: var(--text-body-size-medium);\n line-height: var(--text-body-lineHeight-medium, 1.4285);\n color: var(--fgColor-default);\n text-align: center;\n text-decoration: none;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--borderRadius-medium, var(--borderRadius-small));\n\n /* button resets */\n appearance: none;\n padding-inline: var(--base-size-8);\n padding-block: var(--base-size-6);\n align-items: center;\n\n @media (hover: hover) {\n &:hover {\n text-decoration: none;\n background-color: var(--bgColor-neutral-muted);\n transition: background-color 0.12s ease-out;\n }\n }\n}\n\n.UnderlineItem:focus {\n outline: 2px solid transparent;\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 0 0 2px var(--fgColor-accent);\n\n /* where focus-visible is supported, remove the focus box-shadow */\n &:not(:focus-visible) {\n box-shadow: none;\n }\n}\n\n.UnderlineItem:focus-visible {\n outline: 2px solid transparent;\n /* stylelint-disable-next-line primer/box-shadow */\n box-shadow: inset 0 0 0 2px var(--fgColor-accent);\n}\n\n/* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n.UnderlineItem [data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n white-space: nowrap;\n visibility: hidden;\n content: attr(data-content);\n}\n\n.UnderlineItem [data-component='icon'] {\n display: inline-flex;\n color: var(--fgColor-muted);\n align-items: center;\n margin-inline-end: var(--base-size-8);\n}\n\n.UnderlineItem [data-component='counter'] {\n margin-inline-start: var(--base-size-8);\n display: flex;\n align-items: center;\n}\n\n.UnderlineItem::after {\n position: absolute;\n right: 50%;\n\n /* TODO: see if we can simplify this positioning */\n\n /* 48px total height / 2 (24px) + 1px */\n /* stylelint-disable-next-line primer/spacing */\n bottom: calc(50% - calc(var(--control-xlarge-size, var(--base-size-48)) / 2 + 1px));\n width: 100%;\n height: 2px;\n pointer-events: none;\n content: '';\n background-color: transparent;\n border-radius: 0;\n transform: translate(50%, -50%);\n}\n\n.UnderlineItem[aria-current]:not([aria-current='false']) [data-component='text'],\n.UnderlineItem[aria-selected='true'] [data-component='text'] {\n font-weight: var(--base-text-weight-semibold);\n}\n\n.UnderlineItem[aria-current]:not([aria-current='false'])::after,\n.UnderlineItem[aria-selected='true']::after {\n /* stylelint-disable-next-line primer/colors */\n background-color: var(--underlineNav-borderColor-active, var(--color-primer-border-active, #fd8c73));\n\n @media (forced-colors: active) {\n /* Support for Window Force Color Mode https://learn.microsoft.com/en-us/fluent-ui/web-components/design-system/high-contrast */\n background-color: LinkText;\n }\n}\n\n.LoadingCounter {\n display: inline-block;\n width: 1.5rem;\n height: 1rem;\n /* 16px */\n background-color: var(--bgColor-neutral-muted);\n border-color: var(--borderColor-default);\n /* stylelint-disable-next-line primer/borders */\n border-radius: 20px;\n animation: loadingCounterKeyFrames 1.2s ease-in-out infinite alternate;\n}\n\n@keyframes loadingCounterKeyFrames {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0.2;\n }\n}\n"]}