@dxos/react-ui 0.8.4-main.406dc2a → 0.8.4-main.548089c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{chunk-KX5JDELJ.mjs → chunk-YG7RAH7A.mjs} +67 -45
- package/dist/lib/browser/chunk-YG7RAH7A.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node-esm/{chunk-3HDQYL5S.mjs → chunk-FL2ZT5KB.mjs} +67 -45
- package/dist/lib/node-esm/chunk-FL2ZT5KB.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -2
- package/dist/lib/node-esm/testing/index.mjs.map +2 -2
- package/dist/types/src/components/Buttons/IconButton.d.ts +0 -1
- package/dist/types/src/components/Buttons/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Icon/Icon.stories.d.ts +17 -0
- package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -0
- package/dist/types/src/components/Main/Main.d.ts +8 -8
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +4 -2
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -14
- package/src/components/Buttons/IconButton.tsx +11 -11
- package/src/components/Icon/Icon.stories.tsx +113 -0
- package/src/components/Icon/Icon.tsx +1 -1
- package/src/components/Lists/List.stories.tsx +1 -1
- package/src/components/Main/Main.tsx +13 -13
- package/src/components/Menus/DropdownMenu.tsx +18 -1
- package/src/components/Popover/Popover.tsx +17 -0
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/Toolbar/Toolbar.stories.tsx +1 -3
- package/src/components/Toolbar/Toolbar.tsx +6 -5
- package/src/playground/Custom.stories.tsx +6 -8
- package/src/testing/decorators/withSurfaceVariantsLayout.tsx +1 -1
- package/dist/lib/browser/chunk-KX5JDELJ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-3HDQYL5S.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.548089c",
|
|
4
4
|
"description": "Low-level React components for DXOS, applying a theme to a core group of primitives",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -74,32 +74,33 @@
|
|
|
74
74
|
"keyborg": "^2.5.0",
|
|
75
75
|
"react-i18next": "^11.18.6",
|
|
76
76
|
"react-remove-scroll": "^2.6.0",
|
|
77
|
-
"@dxos/debug": "0.8.4-main.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/react-hooks": "0.8.4-main.
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/react-list": "0.8.4-main.
|
|
83
|
-
"@dxos/react-ui-types": "0.8.4-main.
|
|
84
|
-
"@dxos/util": "0.8.4-main.
|
|
77
|
+
"@dxos/debug": "0.8.4-main.548089c",
|
|
78
|
+
"@dxos/lit-ui": "0.8.4-main.548089c",
|
|
79
|
+
"@dxos/react-hooks": "0.8.4-main.548089c",
|
|
80
|
+
"@dxos/log": "0.8.4-main.548089c",
|
|
81
|
+
"@dxos/react-input": "0.8.4-main.548089c",
|
|
82
|
+
"@dxos/react-list": "0.8.4-main.548089c",
|
|
83
|
+
"@dxos/react-ui-types": "0.8.4-main.548089c",
|
|
84
|
+
"@dxos/util": "0.8.4-main.548089c"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@dnd-kit/core": "^6.0.5",
|
|
88
88
|
"@dnd-kit/sortable": "^7.0.1",
|
|
89
89
|
"@dnd-kit/utilities": "^3.2.0",
|
|
90
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
90
91
|
"@types/react": "~19.2.2",
|
|
91
|
-
"@types/react-dom": "~19.2.
|
|
92
|
+
"@types/react-dom": "~19.2.2",
|
|
92
93
|
"react": "~19.2.0",
|
|
93
94
|
"react-dom": "~19.2.0",
|
|
94
95
|
"vite": "7.1.9",
|
|
95
|
-
"@dxos/
|
|
96
|
-
"@dxos/util": "0.8.4-main.
|
|
97
|
-
"@dxos/
|
|
96
|
+
"@dxos/random": "0.8.4-main.548089c",
|
|
97
|
+
"@dxos/util": "0.8.4-main.548089c",
|
|
98
|
+
"@dxos/react-ui-theme": "0.8.4-main.548089c"
|
|
98
99
|
},
|
|
99
100
|
"peerDependencies": {
|
|
100
101
|
"react": "^19.0.0",
|
|
101
102
|
"react-dom": "^19.0.0",
|
|
102
|
-
"@dxos/react-ui-theme": "0.8.4-main.
|
|
103
|
+
"@dxos/react-ui-theme": "0.8.4-main.548089c"
|
|
103
104
|
},
|
|
104
105
|
"publishConfig": {
|
|
105
106
|
"access": "public"
|
|
@@ -18,15 +18,23 @@ type IconButtonProps = Omit<ButtonProps, 'children'> &
|
|
|
18
18
|
noTooltip?: boolean;
|
|
19
19
|
caretDown?: boolean;
|
|
20
20
|
iconClassNames?: ThemedClassName<any>['classNames'];
|
|
21
|
-
tooltipPortal?: boolean;
|
|
22
21
|
tooltipSide?: TooltipSide;
|
|
23
22
|
};
|
|
24
23
|
|
|
24
|
+
const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props, forwardedRef) =>
|
|
25
|
+
props.iconOnly ? (
|
|
26
|
+
<IconOnlyButton {...props} ref={forwardedRef} />
|
|
27
|
+
) : (
|
|
28
|
+
<LabelledIconButton {...props} ref={forwardedRef} />
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
|
|
25
32
|
const IconOnlyButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
26
|
-
({ noTooltip,
|
|
33
|
+
({ noTooltip, tooltipSide, ...props }, forwardedRef) => {
|
|
27
34
|
if (noTooltip) {
|
|
28
35
|
return <LabelledIconButton {...props} ref={forwardedRef} />;
|
|
29
36
|
}
|
|
37
|
+
|
|
30
38
|
return (
|
|
31
39
|
<Tooltip.Trigger asChild content={props.label} side={tooltipSide}>
|
|
32
40
|
<LabelledIconButton {...props} ref={forwardedRef} />
|
|
@@ -36,7 +44,7 @@ const IconOnlyButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
|
36
44
|
);
|
|
37
45
|
|
|
38
46
|
const LabelledIconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
39
|
-
({ icon, size, iconOnly, label, classNames, iconClassNames, caretDown, ...props }, forwardedRef) => {
|
|
47
|
+
({ icon, size = 5, iconOnly, label, classNames, iconClassNames, caretDown, ...props }, forwardedRef) => {
|
|
40
48
|
const { tx } = useThemeContext();
|
|
41
49
|
return (
|
|
42
50
|
<Button {...props} classNames={tx('iconButton.root', 'iconButton', { iconOnly }, classNames)} ref={forwardedRef}>
|
|
@@ -48,14 +56,6 @@ const LabelledIconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
|
48
56
|
},
|
|
49
57
|
);
|
|
50
58
|
|
|
51
|
-
const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props, forwardedRef) =>
|
|
52
|
-
props.iconOnly ? (
|
|
53
|
-
<IconOnlyButton {...props} ref={forwardedRef} />
|
|
54
|
-
) : (
|
|
55
|
-
<LabelledIconButton {...props} ref={forwardedRef} />
|
|
56
|
-
),
|
|
57
|
-
);
|
|
58
|
-
|
|
59
59
|
export { IconButton };
|
|
60
60
|
|
|
61
61
|
export type { IconButtonProps };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { IconBase, type IconProps, type IconWeight } from '@phosphor-icons/react';
|
|
6
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
+
import React, { type FC, type ReactElement, type SVGProps, forwardRef } from 'react';
|
|
8
|
+
|
|
9
|
+
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
10
|
+
|
|
11
|
+
import { withTheme } from '../../testing';
|
|
12
|
+
|
|
13
|
+
import { Icon } from './Icon';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create icon from serializable data.
|
|
17
|
+
* https://github.com/phosphor-icons/react#custom-icons
|
|
18
|
+
* https://github.com/phosphor-icons/core/tree/main/assets
|
|
19
|
+
*/
|
|
20
|
+
const createIcon = ({
|
|
21
|
+
name,
|
|
22
|
+
weights,
|
|
23
|
+
}: {
|
|
24
|
+
name: string;
|
|
25
|
+
weights: Record<string, SVGProps<SVGPathElement>[]>;
|
|
26
|
+
}): FC<IconProps> => {
|
|
27
|
+
const CustomIcon = forwardRef<SVGSVGElement, IconProps>((props, ref) => (
|
|
28
|
+
<IconBase
|
|
29
|
+
ref={ref}
|
|
30
|
+
{...props}
|
|
31
|
+
weights={
|
|
32
|
+
new Map<IconWeight, ReactElement>(
|
|
33
|
+
Object.entries(weights).map(
|
|
34
|
+
([key, paths]) =>
|
|
35
|
+
[
|
|
36
|
+
key,
|
|
37
|
+
<>
|
|
38
|
+
{paths.map((props, i) => (
|
|
39
|
+
<path key={`${key}-${i}`} {...props} />
|
|
40
|
+
))}
|
|
41
|
+
</>,
|
|
42
|
+
] as [IconWeight, ReactElement],
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
));
|
|
48
|
+
|
|
49
|
+
CustomIcon.displayName = name;
|
|
50
|
+
return CustomIcon;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const DefaultStory = ({ CustomIcon }: { CustomIcon: FC<IconProps> }) => {
|
|
54
|
+
return (
|
|
55
|
+
<div className='grid grid-cols-2 gap-8'>
|
|
56
|
+
<CustomIcon weight={'regular'} className={mx(getSize(16))} />
|
|
57
|
+
<Icon icon='ph--github-logo--regular' classNames={mx(getSize(16))} />
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const meta = {
|
|
63
|
+
title: 'ui/react-ui-core/Icon',
|
|
64
|
+
render: DefaultStory,
|
|
65
|
+
decorators: [withTheme],
|
|
66
|
+
parameters: {
|
|
67
|
+
layout: 'centered',
|
|
68
|
+
},
|
|
69
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
70
|
+
|
|
71
|
+
export default meta;
|
|
72
|
+
|
|
73
|
+
type Story = StoryObj<typeof meta>;
|
|
74
|
+
|
|
75
|
+
export const Default: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
CustomIcon: createIcon({
|
|
78
|
+
name: 'GithubLogo',
|
|
79
|
+
weights: {
|
|
80
|
+
// https://github.com/phosphor-icons/core/tree/main/assets
|
|
81
|
+
// <path d="M119.83,56A52,52,0,0,0,76,32a51.92,51.92,0,0,0-3.49,44.7A49.28,49.28,0,0,0,64,104v8a48,48,0,0,0,48,48h48a48,48,0,0,0,48-48v-8a49.28,49.28,0,0,0-8.51-27.3A51.92,51.92,0,0,0,196,32a52,52,0,0,0-43.83,24Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
82
|
+
// <path d="M104,232V192a32,32,0,0,1,32-32h0a32,32,0,0,1,32,32v40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
83
|
+
// <path d="M104,208H72a32,32,0,0,1-32-32A32,32,0,0,0,8,144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
84
|
+
regular: [
|
|
85
|
+
{
|
|
86
|
+
d: 'M119.83,56A52,52,0,0,0,76,32a51.92,51.92,0,0,0-3.49,44.7A49.28,49.28,0,0,0,64,104v8a48,48,0,0,0,48,48h48a48,48,0,0,0,48-48v-8a49.28,49.28,0,0,0-8.51-27.3A51.92,51.92,0,0,0,196,32a52,52,0,0,0-43.83,24Z',
|
|
87
|
+
fill: 'none',
|
|
88
|
+
stroke: 'currentColor',
|
|
89
|
+
strokeLinecap: 'round',
|
|
90
|
+
strokeLinejoin: 'round',
|
|
91
|
+
strokeWidth: '16',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
d: 'M104,232V192a32,32,0,0,1,32-32h0a32,32,0,0,1,32,32v40',
|
|
95
|
+
fill: 'none',
|
|
96
|
+
stroke: 'currentColor',
|
|
97
|
+
strokeLinecap: 'round',
|
|
98
|
+
strokeLinejoin: 'round',
|
|
99
|
+
strokeWidth: '16',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
d: 'M104,208H72a32,32,0,0,1-32-32A32,32,0,0,0,8,144',
|
|
103
|
+
fill: 'none',
|
|
104
|
+
stroke: 'currentColor',
|
|
105
|
+
strokeLinecap: 'round',
|
|
106
|
+
strokeLinejoin: 'round',
|
|
107
|
+
strokeWidth: '16',
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
@@ -16,7 +16,7 @@ export type IconProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.s
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export const Icon = memo(
|
|
19
|
-
forwardRef<SVGSVGElement, IconProps>(({ icon, classNames, size, ...props }, forwardedRef) => {
|
|
19
|
+
forwardRef<SVGSVGElement, IconProps>(({ icon, classNames, size = 4, ...props }, forwardedRef) => {
|
|
20
20
|
const { tx } = useThemeContext();
|
|
21
21
|
const href = useIconHref(icon);
|
|
22
22
|
return (
|
|
@@ -229,7 +229,7 @@ export const SelectableListbox: Story = {
|
|
|
229
229
|
onClick={() => setSelectedId(id)}
|
|
230
230
|
onKeyUp={(event) => handleKeyUp(event, id)}
|
|
231
231
|
>
|
|
232
|
-
<ListItem.Heading classNames='flex
|
|
232
|
+
<ListItem.Heading classNames='flex pli-1 items-center grow truncate'>{text}</ListItem.Heading>
|
|
233
233
|
</ListItem.Root>
|
|
234
234
|
))}
|
|
235
235
|
</List>
|
|
@@ -31,22 +31,12 @@ import { type Label, toLocalizedString, useTranslation } from '../ThemeProvider'
|
|
|
31
31
|
|
|
32
32
|
import { useSwipeToDismiss } from './useSwipeToDismiss';
|
|
33
33
|
|
|
34
|
+
const MAIN_NAME = 'Main';
|
|
34
35
|
const MAIN_ROOT_NAME = 'MainRoot';
|
|
35
36
|
const NAVIGATION_SIDEBAR_NAME = 'NavigationSidebar';
|
|
36
37
|
const COMPLEMENTARY_SIDEBAR_NAME = 'ComplementarySidebar';
|
|
37
|
-
const MAIN_NAME = 'Main';
|
|
38
38
|
const GENERIC_CONSUMER_NAME = 'GenericConsumer';
|
|
39
39
|
|
|
40
|
-
type SidebarState = 'expanded' | 'collapsed' | 'closed';
|
|
41
|
-
|
|
42
|
-
type MainContextValue = {
|
|
43
|
-
resizing: boolean;
|
|
44
|
-
navigationSidebarState: SidebarState;
|
|
45
|
-
setNavigationSidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
46
|
-
complementarySidebarState: SidebarState;
|
|
47
|
-
setComplementarySidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
40
|
const landmarkAttr = 'data-main-landmark';
|
|
51
41
|
|
|
52
42
|
/**
|
|
@@ -72,8 +62,8 @@ const useLandmarkMover = (propsOnKeyDown: ComponentPropsWithoutRef<'div'>['onKey
|
|
|
72
62
|
[propsOnKeyDown],
|
|
73
63
|
);
|
|
74
64
|
|
|
75
|
-
// TODO(thure): This was disconnected once before in #8818
|
|
76
|
-
// extension, please ensure the change doesn’t break web, desktop and mobile.
|
|
65
|
+
// TODO(thure): This was disconnected once before in #8818;
|
|
66
|
+
// if this should change again to support the browser extension, please ensure the change doesn’t break web, desktop and mobile.
|
|
77
67
|
const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited', ignoreDefaultKeydown: { Tab: true } });
|
|
78
68
|
|
|
79
69
|
return {
|
|
@@ -84,6 +74,16 @@ const useLandmarkMover = (propsOnKeyDown: ComponentPropsWithoutRef<'div'>['onKey
|
|
|
84
74
|
};
|
|
85
75
|
};
|
|
86
76
|
|
|
77
|
+
type SidebarState = 'expanded' | 'collapsed' | 'closed';
|
|
78
|
+
|
|
79
|
+
type MainContextValue = {
|
|
80
|
+
resizing: boolean;
|
|
81
|
+
navigationSidebarState: SidebarState;
|
|
82
|
+
setNavigationSidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
83
|
+
complementarySidebarState: SidebarState;
|
|
84
|
+
setComplementarySidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
87
|
const [MainProvider, useMainContext] = createContext<MainContextValue>(MAIN_NAME, {
|
|
88
88
|
resizing: false,
|
|
89
89
|
navigationSidebarState: 'closed',
|
|
@@ -25,6 +25,7 @@ import React, {
|
|
|
25
25
|
forwardRef,
|
|
26
26
|
useCallback,
|
|
27
27
|
useEffect,
|
|
28
|
+
useMemo,
|
|
28
29
|
useRef,
|
|
29
30
|
} from 'react';
|
|
30
31
|
|
|
@@ -234,19 +235,35 @@ interface DropdownMenuContentProps extends Omit<MenuContentProps, 'onEntryFocus'
|
|
|
234
235
|
|
|
235
236
|
const DropdownMenuContent = forwardRef<DropdownMenuContentElement, DropdownMenuContentProps>(
|
|
236
237
|
(props: ScopedProps<DropdownMenuContentProps>, forwardedRef) => {
|
|
237
|
-
const { __scopeDropdownMenu, classNames, collisionPadding = 8, ...contentProps } = props;
|
|
238
|
+
const { __scopeDropdownMenu, classNames, collisionPadding = 8, collisionBoundary, ...contentProps } = props;
|
|
238
239
|
const { tx } = useThemeContext();
|
|
239
240
|
const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
|
|
240
241
|
const elevation = useElevationContext();
|
|
241
242
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
242
243
|
const hasInteractedOutsideRef = useRef(false);
|
|
243
244
|
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
245
|
+
|
|
246
|
+
// Check for the closest annotated collision boundary in the DOM tree.
|
|
247
|
+
const computedCollisionBoundary = useMemo(() => {
|
|
248
|
+
const closestBoundary = context.triggerRef.current?.closest(
|
|
249
|
+
'[data-popover-collision-boundary]',
|
|
250
|
+
) as HTMLElement | null;
|
|
251
|
+
return closestBoundary
|
|
252
|
+
? Array.isArray(collisionBoundary)
|
|
253
|
+
? [closestBoundary, ...collisionBoundary]
|
|
254
|
+
: collisionBoundary
|
|
255
|
+
? [closestBoundary, collisionBoundary]
|
|
256
|
+
: [closestBoundary]
|
|
257
|
+
: collisionBoundary;
|
|
258
|
+
}, [context.open, collisionBoundary, context.triggerRef.current]);
|
|
259
|
+
|
|
244
260
|
return (
|
|
245
261
|
<MenuPrimitive.Content
|
|
246
262
|
id={context.contentId}
|
|
247
263
|
aria-labelledby={context.triggerId}
|
|
248
264
|
{...menuScope}
|
|
249
265
|
{...contentProps}
|
|
266
|
+
collisionBoundary={computedCollisionBoundary}
|
|
250
267
|
collisionPadding={safeCollisionPadding}
|
|
251
268
|
ref={forwardedRef}
|
|
252
269
|
onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
@@ -31,6 +31,7 @@ import React, {
|
|
|
31
31
|
forwardRef,
|
|
32
32
|
useCallback,
|
|
33
33
|
useEffect,
|
|
34
|
+
useMemo,
|
|
34
35
|
useRef,
|
|
35
36
|
useState,
|
|
36
37
|
} from 'react';
|
|
@@ -432,6 +433,7 @@ const PopoverContentImpl = forwardRef<PopoverContentImplElement, PopoverContentI
|
|
|
432
433
|
onFocusOutside,
|
|
433
434
|
onInteractOutside,
|
|
434
435
|
collisionPadding = 8,
|
|
436
|
+
collisionBoundary,
|
|
435
437
|
classNames,
|
|
436
438
|
...contentProps
|
|
437
439
|
} = props;
|
|
@@ -444,6 +446,20 @@ const PopoverContentImpl = forwardRef<PopoverContentImplElement, PopoverContentI
|
|
|
444
446
|
// Make sure the whole tree has focus guards as our `Popover` may be the last element in the DOM (because of the `Portal`)
|
|
445
447
|
useFocusGuards();
|
|
446
448
|
|
|
449
|
+
// Check for the closest annotated collision boundary in the DOM tree.
|
|
450
|
+
const computedCollisionBoundary = useMemo(() => {
|
|
451
|
+
const closestBoundary = context.triggerRef.current?.closest(
|
|
452
|
+
'[data-popover-collision-boundary]',
|
|
453
|
+
) as HTMLElement | null;
|
|
454
|
+
return closestBoundary
|
|
455
|
+
? Array.isArray(collisionBoundary)
|
|
456
|
+
? [closestBoundary, ...collisionBoundary]
|
|
457
|
+
: collisionBoundary
|
|
458
|
+
? [closestBoundary, collisionBoundary]
|
|
459
|
+
: [closestBoundary]
|
|
460
|
+
: collisionBoundary;
|
|
461
|
+
}, [context.open, collisionBoundary, context.triggerRef.current]);
|
|
462
|
+
|
|
447
463
|
return (
|
|
448
464
|
<FocusScope
|
|
449
465
|
asChild
|
|
@@ -468,6 +484,7 @@ const PopoverContentImpl = forwardRef<PopoverContentImplElement, PopoverContentI
|
|
|
468
484
|
{...popperScope}
|
|
469
485
|
{...contentProps}
|
|
470
486
|
collisionPadding={safeCollisionPadding}
|
|
487
|
+
collisionBoundary={computedCollisionBoundary}
|
|
471
488
|
className={tx('popover.content', 'popover', { elevation }, classNames)}
|
|
472
489
|
ref={forwardedRef}
|
|
473
490
|
style={{
|
|
@@ -108,7 +108,7 @@ const SelectScrollDownButton = forwardRef<HTMLDivElement, SelectScrollDownButton
|
|
|
108
108
|
type SelectViewportProps = ThemedClassName<SelectPrimitive.SelectViewportProps>;
|
|
109
109
|
|
|
110
110
|
const SelectViewport = forwardRef<HTMLDivElement, SelectViewportProps>(
|
|
111
|
-
({ classNames,
|
|
111
|
+
({ classNames, children, ...props }, forwardedRef) => {
|
|
112
112
|
const { tx } = useThemeContext();
|
|
113
113
|
return (
|
|
114
114
|
<SelectPrimitive.SelectViewport
|
|
@@ -63,9 +63,7 @@ const DefaultStory = (props: StorybookToolbarProps) => {
|
|
|
63
63
|
</Toolbar.Button>
|
|
64
64
|
<Toolbar.Separator />
|
|
65
65
|
<Toolbar.Button>Test</Toolbar.Button>
|
|
66
|
-
<Toolbar.
|
|
67
|
-
<Icon icon='ph--arrow-clockwise--regular' />
|
|
68
|
-
</Toolbar.Button>
|
|
66
|
+
<Toolbar.IconButton icon='ph--arrow-clockwise--regular' label='Refresh' iconOnly />
|
|
69
67
|
</Toolbar.Root>
|
|
70
68
|
);
|
|
71
69
|
};
|
|
@@ -24,16 +24,17 @@ import { Separator, type SeparatorProps } from '../Separator';
|
|
|
24
24
|
|
|
25
25
|
type ToolbarRootProps = ThemedClassName<
|
|
26
26
|
ToolbarPrimitive.ToolbarProps & {
|
|
27
|
-
layoutManaged?: boolean;
|
|
28
27
|
textBlockWidth?: boolean;
|
|
28
|
+
layoutManaged?: boolean;
|
|
29
|
+
disabled?: boolean;
|
|
29
30
|
}
|
|
30
31
|
>;
|
|
31
32
|
|
|
32
33
|
const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
|
|
33
|
-
({ classNames, children, layoutManaged, textBlockWidth:
|
|
34
|
+
({ classNames, children, layoutManaged, textBlockWidth: textBlockWidthParam, disabled, ...props }, forwardedRef) => {
|
|
34
35
|
const { tx } = useThemeContext();
|
|
35
|
-
const InnerRoot =
|
|
36
|
-
const innerRootProps =
|
|
36
|
+
const InnerRoot = textBlockWidthParam ? 'div' : Fragment;
|
|
37
|
+
const innerRootProps = textBlockWidthParam
|
|
37
38
|
? { role: 'none', className: tx('toolbar.inner', 'toolbar', { layoutManaged }, classNames) }
|
|
38
39
|
: {};
|
|
39
40
|
|
|
@@ -41,7 +42,7 @@ const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
|
|
|
41
42
|
<ToolbarPrimitive.Root
|
|
42
43
|
{...props}
|
|
43
44
|
data-arrow-keys={props.orientation === 'vertical' ? 'up down' : 'left right'}
|
|
44
|
-
className={tx('toolbar.root', 'toolbar', { layoutManaged }, classNames)}
|
|
45
|
+
className={tx('toolbar.root', 'toolbar', { layoutManaged, disabled }, classNames)}
|
|
45
46
|
ref={forwardedRef}
|
|
46
47
|
>
|
|
47
48
|
<InnerRoot {...innerRootProps}>{children}</InnerRoot>
|
|
@@ -30,7 +30,7 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
|
|
|
30
30
|
iconOnly
|
|
31
31
|
size={7}
|
|
32
32
|
density='coarse'
|
|
33
|
-
classNames='
|
|
33
|
+
classNames='pli-1.5'
|
|
34
34
|
/>
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
@@ -43,7 +43,7 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
|
|
|
43
43
|
</Button>
|
|
44
44
|
</div>
|
|
45
45
|
<div className='flex justify-center'>
|
|
46
|
-
<IconButton {...args} label='Test' icon='ph--atom--regular'
|
|
46
|
+
<IconButton {...args} label='Test' icon='ph--atom--regular' density='fine' classNames='pli-2' />
|
|
47
47
|
</div>
|
|
48
48
|
<div className='flex justify-center'>
|
|
49
49
|
<IconButton
|
|
@@ -51,9 +51,8 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
|
|
|
51
51
|
label='Test'
|
|
52
52
|
icon='ph--atom--regular'
|
|
53
53
|
iconOnly
|
|
54
|
-
size={5}
|
|
55
54
|
density='fine'
|
|
56
|
-
classNames='
|
|
55
|
+
classNames='plb-1 pli-1.5'
|
|
57
56
|
/>
|
|
58
57
|
</div>
|
|
59
58
|
</div>
|
|
@@ -61,7 +60,7 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
|
|
|
61
60
|
{/* Small */}
|
|
62
61
|
<div className='grid grid-cols-3 gap-4'>
|
|
63
62
|
<div className='flex justify-center'>
|
|
64
|
-
<Button {...args} density='fine' classNames={'!h-[24px] !text-[14px] p-0
|
|
63
|
+
<Button {...args} density='fine' classNames={'!h-[24px] !text-[14px] p-0 pli-1.5 min-bs-0'}>
|
|
65
64
|
{children}
|
|
66
65
|
</Button>
|
|
67
66
|
</div>
|
|
@@ -90,18 +89,17 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
|
|
|
90
89
|
|
|
91
90
|
{/* TODO(burdon): Full variant with max width. */}
|
|
92
91
|
<div className='flex justify-center'>
|
|
93
|
-
<Button classNames='
|
|
92
|
+
<Button classNames='is-full max-is-[15rem] rounded' variant='default'>
|
|
94
93
|
Test
|
|
95
94
|
</Button>
|
|
96
95
|
</div>
|
|
97
96
|
<div className='flex justify-center'>
|
|
98
97
|
{/* TODO(burdon): Option to have button on RHS. Default size for icon should be 5 for this (medium) density. */}
|
|
99
98
|
<IconButton
|
|
100
|
-
classNames='
|
|
99
|
+
classNames='is-full max-is-[15rem] rounded'
|
|
101
100
|
variant='primary'
|
|
102
101
|
icon='ph--arrows-clockwise--regular'
|
|
103
102
|
label='Test'
|
|
104
|
-
size={5}
|
|
105
103
|
/>
|
|
106
104
|
</div>
|
|
107
105
|
</div>
|
|
@@ -23,7 +23,7 @@ const Panel = ({
|
|
|
23
23
|
densities,
|
|
24
24
|
className,
|
|
25
25
|
}: { Story: ComponentType } & Config & { className?: string }) => (
|
|
26
|
-
<div className={mx('flex flex-col
|
|
26
|
+
<div className={mx('flex flex-col bs-full p-4 gap-4', className)}>
|
|
27
27
|
{elevations?.map(({ elevation, surface }) =>
|
|
28
28
|
densities?.map((density) => (
|
|
29
29
|
<Container key={`${elevation}--${density}`} surface={surface} elevation={elevation}>
|