@box/blueprint-web 12.119.0 → 12.121.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.
Files changed (29) hide show
  1. package/dist/lib-esm/index.css +387 -162
  2. package/dist/lib-esm/index.d.ts +1 -0
  3. package/dist/lib-esm/index.js +2 -0
  4. package/dist/lib-esm/large-list-v2/index.d.ts +42 -0
  5. package/dist/lib-esm/large-list-v2/index.js +47 -0
  6. package/dist/lib-esm/large-list-v2/large-list-v2-content.d.ts +7 -0
  7. package/dist/lib-esm/large-list-v2/large-list-v2-content.js +23 -0
  8. package/dist/lib-esm/large-list-v2/large-list-v2.d.ts +9 -0
  9. package/dist/lib-esm/large-list-v2/large-list-v2.js +25 -0
  10. package/dist/lib-esm/large-list-v2/types.d.ts +8 -0
  11. package/dist/lib-esm/page/index.d.ts +6 -0
  12. package/dist/lib-esm/page/index.js +5 -1
  13. package/dist/lib-esm/page/page-context.d.ts +19 -2
  14. package/dist/lib-esm/page/page-context.js +29 -3
  15. package/dist/lib-esm/page/page-portal.d.ts +52 -0
  16. package/dist/lib-esm/page/page-portal.js +83 -0
  17. package/dist/lib-esm/page/page-subnavigation.js +4 -1
  18. package/dist/lib-esm/primitives/page-header/page-header.js +8 -2
  19. package/dist/lib-esm/text-button/text-button.js +2 -0
  20. package/dist/lib-esm/text-button/types.d.ts +7 -1
  21. package/dist/lib-esm/util-components/base-grid-list-item/base-grid-list-item-actions.js +1 -1
  22. package/dist/lib-esm/util-components/base-grid-list-item/base-grid-list-item-thumbnail.js +1 -1
  23. package/dist/lib-esm/util-components/base-grid-list-item/base-grid-list-item.js +20 -12
  24. package/dist/lib-esm/util-components/base-grid-list-item/base-grid-list-item.module.js +1 -1
  25. package/dist/lib-esm/util-components/base-grid-list-item/base-grid-list.js +4 -0
  26. package/dist/lib-esm/util-components/base-grid-list-item/types.d.ts +2 -1
  27. package/dist/lib-esm/utils/fast-context.d.ts +2 -0
  28. package/dist/lib-esm/utils/fast-context.js +31 -1
  29. package/package.json +3 -3
@@ -34,6 +34,7 @@ export * from './inline-notice/inline-notice';
34
34
  export * from './inline-table/inline-table';
35
35
  export * from './input-chip';
36
36
  export * from './large-list-item';
37
+ export * from './large-list-v2';
37
38
  export * from './list-item/list-item';
38
39
  export * from './loading-indicator/loading-indicator';
39
40
  export * from './modal';
@@ -42,6 +42,7 @@ export { InlineNotice } from './inline-notice/inline-notice.js';
42
42
  export { InlineTable } from './inline-table/inline-table.js';
43
43
  export { InputChip } from './input-chip/input-chip.js';
44
44
  export { LargeList } from './large-list-item/index.js';
45
+ export { LargeListV2 } from './large-list-v2/index.js';
45
46
  export { ActionCell, Cell, Column, DropIndicator, Row, Table, TableBody, TableHeader } from './list-item/list-item.js';
46
47
  export { LoadingIndicator } from './loading-indicator/loading-indicator.js';
47
48
  export { AlertModal } from './modal/alert-modal.js';
@@ -114,5 +115,6 @@ export { useIsEllipsized } from './utils/useIsEllipsized.js';
114
115
  export { getUniqueId, useUniqueId } from './utils/useUniqueId.js';
115
116
  export { VisuallyHidden } from './visually-hidden/visually-hidden.js';
116
117
  export { useMainSectionSidebar, usePageNavigation } from './page/page-context.js';
118
+ export { PageHeaderEndElementsPortal, PageHeaderStartElementsPortal, PageSubNavigationPortal } from './page/page-portal.js';
117
119
  export { useNotification } from './primitives/notification/notification-provider.js';
118
120
  export { useTabs } from './primitives/tabs/use-tabs.js';
@@ -0,0 +1,42 @@
1
+ export type { LargeListV2ActionIconButtonProps, LargeListV2ActionsProps, LargeListV2HeaderProps, LargeListV2ItemProps, LargeListV2Props, LargeListV2SubtitleProps, LargeListV2ThumbnailProps, } from './types';
2
+ /**
3
+ * LargeListV2 - A modernized horizontal list component for displaying items in a compact row layout.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * <LargeListV2 aria-label="Files" selectionMode="multiple">
8
+ * <LargeListV2.Item id="1" textValue="Document.pdf">
9
+ * <LargeListV2.Thumbnail fileExtension="pdf" fileCategory="pdf">
10
+ * <img src="/thumbnail.jpg" alt="Document preview" />
11
+ * </LargeListV2.Thumbnail>
12
+ * <LargeListV2.Content>
13
+ * <LargeListV2.Header>Document.pdf</LargeListV2.Header>
14
+ * <LargeListV2.Subtitle>Modified 2 days ago</LargeListV2.Subtitle>
15
+ * </LargeListV2.Content>
16
+ * <LargeListV2.Actions>
17
+ * <LargeListV2.ActionIconButton icon={MoreIcon} aria-label="More actions" />
18
+ * </LargeListV2.Actions>
19
+ * </LargeListV2.Item>
20
+ * </LargeListV2>
21
+ * ```
22
+ */
23
+ export declare const LargeListV2: import("react").ForwardRefExoticComponent<import("./types").LargeListV2Props & import("react").RefAttributes<HTMLDivElement>> & {
24
+ /** An individual item in the list. */
25
+ Item: import("react").ForwardRefExoticComponent<import("../util-components/base-grid-list-item").BaseGridListItemProps & import("react").RefAttributes<HTMLDivElement>>;
26
+ /** Styled wrapper for the thumbnail/icon (4:3 aspect ratio). */
27
+ Thumbnail: import("react").ForwardRefExoticComponent<Omit<import("../util-components/base-grid-list-item").BaseGridListThumbnailProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
28
+ /** Content wrapper that groups header and subtitle. */
29
+ Content: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
30
+ ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
31
+ }, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
32
+ /** Title/name of the item (15px/20px). */
33
+ Header: import("react").ForwardRefExoticComponent<Omit<import("../util-components/base-grid-list-item").BaseGridListHeaderProps, "ref"> & import("react").RefAttributes<HTMLSpanElement>>;
34
+ /** Secondary text below the header (13px/20px). */
35
+ Subtitle: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
36
+ ref?: ((instance: HTMLSpanElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLSpanElement> | null | undefined;
37
+ }, "ref"> & import("react").RefAttributes<HTMLSpanElement>>;
38
+ /** Container for action buttons and selection checkbox. */
39
+ Actions: import("react").ForwardRefExoticComponent<Omit<import("../util-components/base-grid-list-item").BaseGridListActionsProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
40
+ /** Icon button for item actions (32x32px). */
41
+ ActionIconButton: import("react").ForwardRefExoticComponent<(Omit<import("../primitives/icon-button/types").IconButtonVariantsProps, "ref"> | Omit<import("../primitives/icon-button/types").IconButtonSmallUtilityVariantProps, "ref">) & import("react").RefAttributes<HTMLButtonElement>>;
42
+ };
@@ -0,0 +1,47 @@
1
+ import { BaseGridListItem } from '../util-components/base-grid-list-item/base-grid-list-item.js';
2
+ import { BaseGridListActionIconButton, BaseGridListActions } from '../util-components/base-grid-list-item/base-grid-list-item-actions.js';
3
+ import { BaseGridListHeader } from '../util-components/base-grid-list-item/base-grid-list-item-header.js';
4
+ import { BaseGridListSubtitle } from '../util-components/base-grid-list-item/base-grid-list-item-subtitle.js';
5
+ import { BaseGridListThumbnail } from '../util-components/base-grid-list-item/base-grid-list-item-thumbnail.js';
6
+ import { LargeListV2Root } from './large-list-v2.js';
7
+ import { LargeListV2Content } from './large-list-v2-content.js';
8
+
9
+ /**
10
+ * LargeListV2 - A modernized horizontal list component for displaying items in a compact row layout.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <LargeListV2 aria-label="Files" selectionMode="multiple">
15
+ * <LargeListV2.Item id="1" textValue="Document.pdf">
16
+ * <LargeListV2.Thumbnail fileExtension="pdf" fileCategory="pdf">
17
+ * <img src="/thumbnail.jpg" alt="Document preview" />
18
+ * </LargeListV2.Thumbnail>
19
+ * <LargeListV2.Content>
20
+ * <LargeListV2.Header>Document.pdf</LargeListV2.Header>
21
+ * <LargeListV2.Subtitle>Modified 2 days ago</LargeListV2.Subtitle>
22
+ * </LargeListV2.Content>
23
+ * <LargeListV2.Actions>
24
+ * <LargeListV2.ActionIconButton icon={MoreIcon} aria-label="More actions" />
25
+ * </LargeListV2.Actions>
26
+ * </LargeListV2.Item>
27
+ * </LargeListV2>
28
+ * ```
29
+ */
30
+ const LargeListV2 = Object.assign(LargeListV2Root, {
31
+ /** An individual item in the list. */
32
+ Item: BaseGridListItem,
33
+ /** Styled wrapper for the thumbnail/icon (4:3 aspect ratio). */
34
+ Thumbnail: BaseGridListThumbnail,
35
+ /** Content wrapper that groups header and subtitle. */
36
+ Content: LargeListV2Content,
37
+ /** Title/name of the item (15px/20px). */
38
+ Header: BaseGridListHeader,
39
+ /** Secondary text below the header (13px/20px). */
40
+ Subtitle: BaseGridListSubtitle,
41
+ /** Container for action buttons and selection checkbox. */
42
+ Actions: BaseGridListActions,
43
+ /** Icon button for item actions (32x32px). */
44
+ ActionIconButton: BaseGridListActionIconButton
45
+ });
46
+
47
+ export { LargeListV2 };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Content wrapper for LargeListV2 items.
3
+ * Groups the header and subtitle in a vertical stack.
4
+ */
5
+ export declare const LargeListV2Content: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
6
+ ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
7
+ }, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,23 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { forwardRef } from 'react';
3
+ import styles from '../util-components/base-grid-list-item/base-grid-list-item.module.js';
4
+
5
+ /**
6
+ * Content wrapper for LargeListV2 items.
7
+ * Groups the header and subtitle in a vertical stack.
8
+ */
9
+ const LargeListV2Content = /*#__PURE__*/forwardRef(function LargeListV2Content(props, ref) {
10
+ const {
11
+ children,
12
+ className,
13
+ ...rest
14
+ } = props;
15
+ return jsx("div", {
16
+ ...rest,
17
+ ref: ref,
18
+ className: `${styles.content} ${className ?? ''}`,
19
+ children: children
20
+ });
21
+ });
22
+
23
+ export { LargeListV2Content };
@@ -0,0 +1,9 @@
1
+ import { type LargeListV2Props } from './types';
2
+ /**
3
+ * LargeListV2 is a modernized horizontal list component for displaying items in a compact row layout.
4
+ * Each item displays a thumbnail on the left, content (title/subtitle) in the middle,
5
+ * and actions on the right.
6
+ *
7
+ * This component ships post-UI-Uplift and uses modern Blueprint tokens by default.
8
+ */
9
+ export declare const LargeListV2Root: import("react").ForwardRefExoticComponent<LargeListV2Props & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,25 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { forwardRef } from 'react';
3
+ import { BaseGridList } from '../util-components/base-grid-list-item/base-grid-list.js';
4
+
5
+ /**
6
+ * LargeListV2 is a modernized horizontal list component for displaying items in a compact row layout.
7
+ * Each item displays a thumbnail on the left, content (title/subtitle) in the middle,
8
+ * and actions on the right.
9
+ *
10
+ * This component ships post-UI-Uplift and uses modern Blueprint tokens by default.
11
+ */
12
+ const LargeListV2Root = /*#__PURE__*/forwardRef(function LargeListV2(props, forwardedRef) {
13
+ const {
14
+ children,
15
+ ...rest
16
+ } = props;
17
+ return jsx(BaseGridList, {
18
+ ...rest,
19
+ ref: forwardedRef,
20
+ layoutStyle: "list-v2",
21
+ children: children
22
+ });
23
+ });
24
+
25
+ export { LargeListV2Root };
@@ -0,0 +1,8 @@
1
+ import { type BaseGridListActionIconButtonProps, type BaseGridListActionsProps, type BaseGridListHeaderProps, type BaseGridListItemProps, type BaseGridListProps, type BaseGridListSubtitleProps, type BaseGridListThumbnailProps } from '../util-components/base-grid-list-item/types';
2
+ export type LargeListV2Props = Omit<BaseGridListProps, 'layoutStyle' | 'centerText' | 'variant'>;
3
+ export type LargeListV2ItemProps = BaseGridListItemProps;
4
+ export type LargeListV2ThumbnailProps = BaseGridListThumbnailProps;
5
+ export type LargeListV2HeaderProps = BaseGridListHeaderProps;
6
+ export type LargeListV2SubtitleProps = BaseGridListSubtitleProps;
7
+ export type LargeListV2ActionsProps = BaseGridListActionsProps;
8
+ export type LargeListV2ActionIconButtonProps = BaseGridListActionIconButtonProps;
@@ -1,4 +1,7 @@
1
1
  export { useMainSectionSidebar, usePageNavigation } from './page-context';
2
+ export type { PagePortalRefs } from './page-context';
3
+ export { PageHeaderEndElementsPortal, PageHeaderStartElementsPortal, PageSubNavigationPortal } from './page-portal';
4
+ export type { PagePortalProps } from './page-portal';
2
5
  export * from './types';
3
6
  export declare const Page: import("react").ForwardRefExoticComponent<import("./types").PageLayoutProps & import("react").RefAttributes<HTMLDivElement>> & {
4
7
  /**
@@ -27,10 +30,13 @@ export declare const Page: import("react").ForwardRefExoticComponent<import("./t
27
30
  };
28
31
  /**
29
32
  * Sub navigation area of the page.
33
+ * Content can be portaled here using PageSubNavigationPortal from child routes.
30
34
  */
31
35
  SubNavigation: import("react").ForwardRefExoticComponent<import("./types").PageSubNavigationProps & import("react").RefAttributes<HTMLDivElement>>;
32
36
  /**
33
37
  * Page header with title and actions.
38
+ * Content can be portaled to StartElements and EndElements using
39
+ * PageHeaderStartElementsPortal and PageHeaderEndElementsPortal from child routes.
34
40
  */
35
41
  PageHeader: ((props: import("./types").PagePageHeaderProps) => import("react/jsx-runtime").JSX.Element) & {
36
42
  StartElements: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -4,8 +4,9 @@ import { PageNavigation } from './page-navigation.js';
4
4
  import { PagePageHeader } from './page-page-header.js';
5
5
  import { PageRoot } from './page-root.js';
6
6
  import { PageSubNavigation } from './page-subnavigation.js';
7
- import 'react/jsx-runtime';
8
7
  import 'react';
8
+ import 'react/jsx-runtime';
9
+ export { PageHeaderEndElementsPortal, PageHeaderStartElementsPortal, PageSubNavigationPortal } from './page-portal.js';
9
10
 
10
11
  const Page = Object.assign(PageRoot, {
11
12
  /**
@@ -28,10 +29,13 @@ const Page = Object.assign(PageRoot, {
28
29
  MainSection,
29
30
  /**
30
31
  * Sub navigation area of the page.
32
+ * Content can be portaled here using PageSubNavigationPortal from child routes.
31
33
  */
32
34
  SubNavigation: PageSubNavigation,
33
35
  /**
34
36
  * Page header with title and actions.
37
+ * Content can be portaled to StartElements and EndElements using
38
+ * PageHeaderStartElementsPortal and PageHeaderEndElementsPortal from child routes.
35
39
  */
36
40
  PageHeader: PagePageHeader
37
41
  });
@@ -1,4 +1,13 @@
1
- export interface PageFastContextValuesType {
1
+ import { type ForwardedRef } from 'react';
2
+ export interface PagePortalRefs {
3
+ /** Reference to the PageHeader.StartElements container */
4
+ pageHeaderStartElementsRef: HTMLDivElement | null;
5
+ /** Reference to the PageHeader.EndElements container */
6
+ pageHeaderEndElementsRef: HTMLDivElement | null;
7
+ /** Reference to the PageSubNavigation container */
8
+ pageSubNavigationRef: HTMLDivElement | null;
9
+ }
10
+ export interface PageFastContextValuesType extends PagePortalRefs {
2
11
  navigationExpanded: boolean;
3
12
  pageContainer: HTMLElement | null;
4
13
  globalHeaderContainer: HTMLDivElement | null;
@@ -6,7 +15,7 @@ export interface PageFastContextValuesType {
6
15
  }
7
16
  export declare const PageProvider: ({ children }: {
8
17
  children: React.ReactNode;
9
- }) => import("react/jsx-runtime").JSX.Element, usePageStore: <SelectorOutput>(selector: (store: PageFastContextValuesType) => SelectorOutput) => [SelectorOutput, (value: Partial<PageFastContextValuesType>) => void], usePageStoreSetter: () => (value: Partial<PageFastContextValuesType>) => void;
18
+ }) => import("react/jsx-runtime").JSX.Element, usePageStore: <SelectorOutput>(selector: (store: PageFastContextValuesType) => SelectorOutput) => [SelectorOutput, (value: Partial<PageFastContextValuesType>) => void], usePageStoreSafe: <SelectorOutput>(selector: (store: PageFastContextValuesType) => SelectorOutput) => [SelectorOutput, (value: Partial<PageFastContextValuesType>) => void] | null, usePageStoreSetter: () => (value: Partial<PageFastContextValuesType>) => void, usePageStoreSetterSafe: () => ((value: Partial<PageFastContextValuesType>) => void) | null;
10
19
  export declare const usePageNavigation: () => {
11
20
  navigationExpanded: boolean;
12
21
  setNavigationExpanded: (expanded: boolean) => void;
@@ -17,3 +26,11 @@ export declare const useMainSectionSidebar: () => {
17
26
  setMainSectionSidebarVisible: (visible: boolean) => void;
18
27
  toggleMainSectionSidebarVisible: () => void;
19
28
  };
29
+ /**
30
+ * Hook that creates a callback ref which stores the node in the PageStore
31
+ * and forwards it to an optional forwardedRef.
32
+ *
33
+ * Works both with and without a PageProvider - when used standalone,
34
+ * it simply forwards the ref without storing it.
35
+ */
36
+ export declare function usePageStoreRef<T extends HTMLElement>(storeKey: keyof PagePortalRefs, forwardedRef: ForwardedRef<T>): (node: T | null) => void;
@@ -1,14 +1,20 @@
1
+ import { useCallback } from 'react';
1
2
  import { createFastContext } from '../utils/fast-context.js';
2
3
 
3
4
  const {
4
5
  Provider: PageProvider,
5
6
  useStore: usePageStore,
6
- useStoreSetter: usePageStoreSetter
7
+ useStoreSafe: usePageStoreSafe,
8
+ useStoreSetter: usePageStoreSetter,
9
+ useStoreSetterSafe: usePageStoreSetterSafe
7
10
  } = createFastContext({
8
11
  globalHeaderContainer: null,
9
12
  mainSectionSidebarVisible: true,
10
13
  navigationExpanded: true,
11
- pageContainer: null
14
+ pageContainer: null,
15
+ pageHeaderStartElementsRef: null,
16
+ pageHeaderEndElementsRef: null,
17
+ pageSubNavigationRef: null
12
18
  });
13
19
  const usePageNavigation = () => {
14
20
  const [navigationExpanded, setPageStore] = usePageStore(store => store.navigationExpanded);
@@ -46,5 +52,25 @@ const useMainSectionSidebar = () => {
46
52
  toggleMainSectionSidebarVisible
47
53
  };
48
54
  };
55
+ /**
56
+ * Hook that creates a callback ref which stores the node in the PageStore
57
+ * and forwards it to an optional forwardedRef.
58
+ *
59
+ * Works both with and without a PageProvider - when used standalone,
60
+ * it simply forwards the ref without storing it.
61
+ */
62
+ function usePageStoreRef(storeKey, forwardedRef) {
63
+ const setPageStore = usePageStoreSetterSafe();
64
+ return useCallback(node => {
65
+ setPageStore?.({
66
+ [storeKey]: node
67
+ });
68
+ if (typeof forwardedRef === 'function') {
69
+ forwardedRef(node);
70
+ } else if (forwardedRef) {
71
+ forwardedRef.current = node;
72
+ }
73
+ }, [forwardedRef, setPageStore, storeKey]);
74
+ }
49
75
 
50
- export { PageProvider, useMainSectionSidebar, usePageNavigation, usePageStore, usePageStoreSetter };
76
+ export { PageProvider, useMainSectionSidebar, usePageNavigation, usePageStore, usePageStoreRef, usePageStoreSafe, usePageStoreSetter, usePageStoreSetterSafe };
@@ -0,0 +1,52 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface PagePortalProps {
3
+ /** Content to render in the portal target location. */
4
+ children: ReactNode;
5
+ /**
6
+ * Content to render before the portal target is available (e.g., during SSR or before mount).
7
+ * @default null
8
+ */
9
+ fallback?: ReactNode;
10
+ /**
11
+ * When `true`, children are portaled to the target Page slot.
12
+ * When `false`, children render in place without portaling (useful for feature flags or gradual migration).
13
+ * @default true
14
+ */
15
+ isPortalActive?: boolean;
16
+ }
17
+ /**
18
+ * Portal to Page.PageHeader.StartElements
19
+ * Use this to render breadcrumbs, titles, etc. from child routes.
20
+ *
21
+ * @example Conditionally enable portal based on feature flag
22
+ * ```tsx
23
+ * <PageHeaderStartElementsPortal isPortalActive={featureEnabled}>
24
+ * <Breadcrumb>Home / Settings</Breadcrumb>
25
+ * </PageHeaderStartElementsPortal>
26
+ * ```
27
+ */
28
+ export declare const PageHeaderStartElementsPortal: import("react").ForwardRefExoticComponent<PagePortalProps & import("react").RefAttributes<HTMLDivElement>>;
29
+ /**
30
+ * Portal to Page.PageHeader.EndElements
31
+ * Use this to render action buttons, status indicators, etc. from child routes.
32
+ *
33
+ * @example Conditionally enable portal based on feature flag
34
+ * ```tsx
35
+ * <PageHeaderEndElementsPortal isPortalActive={featureEnabled}>
36
+ * <Button>Save</Button>
37
+ * </PageHeaderEndElementsPortal>
38
+ * ```
39
+ */
40
+ export declare const PageHeaderEndElementsPortal: import("react").ForwardRefExoticComponent<PagePortalProps & import("react").RefAttributes<HTMLDivElement>>;
41
+ /**
42
+ * Portal to Page.SubNavigation
43
+ * Use this to render sub-tabs, secondary navigation, etc. from child routes.
44
+ *
45
+ * @example Conditionally enable portal based on feature flag
46
+ * ```tsx
47
+ * <PageSubNavigationPortal isPortalActive={featureEnabled}>
48
+ * <ExistingSubNavigation />
49
+ * </PageSubNavigationPortal>
50
+ * ```
51
+ */
52
+ export declare const PageSubNavigationPortal: import("react").ForwardRefExoticComponent<PagePortalProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,83 @@
1
+ import { forwardRef, useState, useRef, useEffect } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+ import { usePageStoreSafe } from './page-context.js';
4
+
5
+ /**
6
+ * Creates a portal component for a specific Page destination.
7
+ * Caches the last valid ref to prevent flashing during route transitions.
8
+ */
9
+ const createPagePortal = (refKey, displayName) => {
10
+ const Component = /*#__PURE__*/forwardRef(({
11
+ children,
12
+ fallback = null,
13
+ isPortalActive = true
14
+ }, forwardedRef) => {
15
+ const [mounted, setMounted] = useState(false);
16
+ const storeResult = usePageStoreSafe(store => store[refKey]);
17
+ const targetRef = storeResult?.[0] ?? null;
18
+ const cachedRef = useRef(null);
19
+ if (targetRef) {
20
+ cachedRef.current = targetRef;
21
+ }
22
+ useEffect(() => {
23
+ const target = targetRef || cachedRef.current;
24
+ if (typeof forwardedRef === 'function') {
25
+ forwardedRef(target);
26
+ } else if (forwardedRef) {
27
+ forwardedRef.current = target;
28
+ }
29
+ }, [targetRef, forwardedRef]);
30
+ useEffect(() => {
31
+ setMounted(true);
32
+ }, []);
33
+ // If no PageProvider or portal is disabled, render children in place
34
+ if (!storeResult || !isPortalActive) {
35
+ return children;
36
+ }
37
+ const portalTarget = targetRef || cachedRef.current;
38
+ if (!mounted || !portalTarget) {
39
+ return fallback;
40
+ }
41
+ return /*#__PURE__*/createPortal(children, portalTarget);
42
+ });
43
+ Component.displayName = displayName;
44
+ return Component;
45
+ };
46
+ /**
47
+ * Portal to Page.PageHeader.StartElements
48
+ * Use this to render breadcrumbs, titles, etc. from child routes.
49
+ *
50
+ * @example Conditionally enable portal based on feature flag
51
+ * ```tsx
52
+ * <PageHeaderStartElementsPortal isPortalActive={featureEnabled}>
53
+ * <Breadcrumb>Home / Settings</Breadcrumb>
54
+ * </PageHeaderStartElementsPortal>
55
+ * ```
56
+ */
57
+ const PageHeaderStartElementsPortal = createPagePortal('pageHeaderStartElementsRef', 'PageHeaderStartElementsPortal');
58
+ /**
59
+ * Portal to Page.PageHeader.EndElements
60
+ * Use this to render action buttons, status indicators, etc. from child routes.
61
+ *
62
+ * @example Conditionally enable portal based on feature flag
63
+ * ```tsx
64
+ * <PageHeaderEndElementsPortal isPortalActive={featureEnabled}>
65
+ * <Button>Save</Button>
66
+ * </PageHeaderEndElementsPortal>
67
+ * ```
68
+ */
69
+ const PageHeaderEndElementsPortal = createPagePortal('pageHeaderEndElementsRef', 'PageHeaderEndElementsPortal');
70
+ /**
71
+ * Portal to Page.SubNavigation
72
+ * Use this to render sub-tabs, secondary navigation, etc. from child routes.
73
+ *
74
+ * @example Conditionally enable portal based on feature flag
75
+ * ```tsx
76
+ * <PageSubNavigationPortal isPortalActive={featureEnabled}>
77
+ * <ExistingSubNavigation />
78
+ * </PageSubNavigationPortal>
79
+ * ```
80
+ */
81
+ const PageSubNavigationPortal = createPagePortal('pageSubNavigationRef', 'PageSubNavigationPortal');
82
+
83
+ export { PageHeaderEndElementsPortal, PageHeaderStartElementsPortal, PageSubNavigationPortal };
@@ -1,15 +1,18 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef } from 'react';
3
+ import { usePageStoreRef } from './page-context.js';
3
4
 
4
5
  const PageSubNavigation = /*#__PURE__*/forwardRef(({
5
6
  className,
6
7
  ...rest
7
8
  }, forwardedRef) => {
9
+ const setRef = usePageStoreRef('pageSubNavigationRef', forwardedRef);
8
10
  return jsx("div", {
9
11
  ...rest,
10
- ref: forwardedRef,
12
+ ref: setRef,
11
13
  className: className
12
14
  });
13
15
  });
16
+ PageSubNavigation.displayName = 'PageSubNavigation';
14
17
 
15
18
  export { PageSubNavigation };
@@ -2,6 +2,7 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { forwardRef, createElement } from 'react';
4
4
  import { useBlueprintModernization } from '../../blueprint-modernization-context/useBlueprintModernization.js';
5
+ import { usePageStoreRef } from '../../page/page-context.js';
5
6
  import styles from './page-header.module.js';
6
7
 
7
8
  const PageHeaderRoot = /*#__PURE__*/forwardRef((props, forwardedRef) => {
@@ -48,9 +49,10 @@ const PageHeaderStartElements = /*#__PURE__*/forwardRef((props, forwardedRef) =>
48
49
  children,
49
50
  ...rest
50
51
  } = props;
52
+ const setRef = usePageStoreRef('pageHeaderStartElementsRef', forwardedRef);
51
53
  return jsx("div", {
52
54
  ...rest,
53
- ref: forwardedRef,
55
+ ref: setRef,
54
56
  className: clsx(styles.startElements, className),
55
57
  children: children
56
58
  });
@@ -61,13 +63,17 @@ const PageHeaderEndElements = /*#__PURE__*/forwardRef((props, forwardedRef) => {
61
63
  children,
62
64
  ...rest
63
65
  } = props;
66
+ const setRef = usePageStoreRef('pageHeaderEndElementsRef', forwardedRef);
64
67
  return jsx("div", {
65
68
  ...rest,
66
- ref: forwardedRef,
69
+ ref: setRef,
67
70
  className: clsx(styles.endElements, className),
68
71
  children: children
69
72
  });
70
73
  });
74
+ PageHeaderStartElements.displayName = 'PageHeaderStartElements';
75
+ PageHeaderEndElements.displayName = 'PageHeaderEndElements';
76
+ PageHeaderCorner.displayName = 'PageHeaderCorner';
71
77
  const PageHeader = {
72
78
  Root: PageHeaderRoot,
73
79
  StartElements: PageHeaderStartElements,
@@ -15,6 +15,7 @@ const TextButton = /*#__PURE__*/forwardRef((props, ref) => {
15
15
  icon,
16
16
  inheritFont,
17
17
  className,
18
+ textRef,
18
19
  ...rest
19
20
  } = getButtonOptions(props);
20
21
  const {
@@ -31,6 +32,7 @@ const TextButton = /*#__PURE__*/forwardRef((props, ref) => {
31
32
  }, className),
32
33
  "data-modern": enableModernizedComponents ? 'true' : 'false',
33
34
  children: [jsx("span", {
35
+ ref: textRef,
34
36
  className: clsx({
35
37
  [styles.hideTextContent]: loading
36
38
  }),
@@ -1,5 +1,5 @@
1
1
  import { type ButtonProps as AriakitButtonProps } from '@ariakit/react';
2
- import { type FunctionComponent, type PropsWithChildren, type SVGProps } from 'react';
2
+ import { type FunctionComponent, type PropsWithChildren, type Ref, type SVGProps } from 'react';
3
3
  import { type RequireAllOrNone } from 'type-fest';
4
4
  export interface Loading {
5
5
  /** Whether the button is loading. */
@@ -20,5 +20,11 @@ export interface TextButtonBase extends AriakitButtonProps {
20
20
  * When property is falsy, button uses default style.
21
21
  * */
22
22
  inheritFont?: boolean;
23
+ /**
24
+ * Ref to the inner span element that wraps the text content.
25
+ *
26
+ * Useful for measuring text overflow with hooks like `useIsEllipsized`.
27
+ */
28
+ textRef?: Ref<HTMLSpanElement>;
23
29
  }
24
30
  export type TextButtonProps = TextButtonBase & RequireAllOrNone<Loading, keyof Loading>;
@@ -120,7 +120,7 @@ const BaseGridListActions = /*#__PURE__*/forwardRef(function BaseGridListActions
120
120
  if (loading) {
121
121
  return null;
122
122
  }
123
- const isList = layoutStyle === 'list' || layoutStyle === 'small-list';
123
+ const isList = layoutStyle === 'list' || layoutStyle === 'list-v2' || layoutStyle === 'small-list';
124
124
  const isGridV2 = layoutStyle === 'grid-v2';
125
125
  const isSelectionEnabled = selectionMode === 'multiple';
126
126
  const isRenderPropUsed = typeof children === 'function';
@@ -125,7 +125,7 @@ const BaseGridListThumbnail = /*#__PURE__*/forwardRef(function BaseGridListThumb
125
125
  style: extensionColor ? {
126
126
  color: extensionColor
127
127
  } : undefined,
128
- variant: "caption",
128
+ variant: "captionBold",
129
129
  children: normalizedExtension
130
130
  })]
131
131
  })]