@dxos/react-ui 0.7.4 → 0.7.5-labs.071a3e2
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/index.mjs +510 -347
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +766 -614
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +510 -347
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Avatars/Avatar.d.ts +5 -9
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts +1 -2
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Buttons/IconButton.d.ts +6 -2
- package/dist/types/src/components/Buttons/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Dialogs/AlertDialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialogs/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts +5 -6
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +1 -3
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/Lists/List.d.ts +2 -0
- package/dist/types/src/components/Lists/List.d.ts.map +1 -1
- package/dist/types/src/components/Lists/ListDropIndicator.d.ts +13 -0
- package/dist/types/src/components/Lists/ListDropIndicator.d.ts.map +1 -0
- package/dist/types/src/components/Lists/Tree.d.ts +2 -0
- package/dist/types/src/components/Lists/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Lists/TreeDropIndicator.d.ts +8 -0
- package/dist/types/src/components/Lists/TreeDropIndicator.d.ts.map +1 -0
- package/dist/types/src/components/Main/Main.d.ts +35 -24
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.stories.d.ts +1 -1
- package/dist/types/src/components/Menus/ContextMenu.d.ts.map +1 -1
- package/dist/types/src/components/Menus/DropdownMenu.d.ts +2 -6
- 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/Select/Select.d.ts.map +1 -1
- package/dist/types/src/components/Separator/Separator.d.ts +3 -1
- package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.stories.d.ts +12 -5
- package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +4 -2
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -0
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +15 -5
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +7 -2
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +13 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useSafeArea.d.ts +9 -0
- package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -0
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts +10 -0
- package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -0
- package/dist/types/src/hooks/useVisualViewport.d.ts +1 -1
- package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
- package/dist/types/src/util/ThemedClassName.d.ts +1 -1
- package/dist/types/src/util/ThemedClassName.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +43 -42
- package/src/components/Avatars/Avatar.tsx +3 -6
- package/src/components/Buttons/IconButton.tsx +25 -7
- package/src/components/Clipboard/CopyButton.tsx +1 -1
- package/src/components/Dialogs/AlertDialog.tsx +6 -2
- package/src/components/Dialogs/Dialog.tsx +7 -11
- package/src/components/Input/Input.stories.tsx +4 -6
- package/src/components/Input/Input.tsx +29 -44
- package/src/components/Lists/List.stories.tsx +2 -2
- package/src/components/Lists/List.tsx +3 -0
- package/src/components/Lists/ListDropIndicator.tsx +70 -0
- package/src/components/Lists/Tree.tsx +3 -0
- package/src/components/Lists/TreeDropIndicator.tsx +70 -0
- package/src/components/Main/Main.stories.tsx +1 -1
- package/src/components/Main/Main.tsx +79 -110
- package/src/components/Menus/ContextMenu.tsx +8 -6
- package/src/components/Menus/DropdownMenu.tsx +7 -4
- package/src/components/Popover/Popover.tsx +8 -2
- package/src/components/ScrollArea/ScrollArea.stories.tsx +2 -2
- package/src/components/Select/Select.tsx +7 -3
- package/src/components/Separator/Separator.tsx +14 -11
- package/src/components/Tag/Tag.stories.tsx +20 -31
- package/src/components/Tag/Tag.tsx +15 -6
- package/src/components/ThemeProvider/ThemeProvider.tsx +13 -5
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Toolbar/Toolbar.tsx +40 -10
- package/src/components/Tooltip/Tooltip.stories.tsx +13 -2
- package/src/components/Tooltip/Tooltip.tsx +18 -13
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSafeArea.ts +25 -0
- package/src/hooks/useSafeCollisionPadding.ts +39 -0
- package/src/hooks/useVisualViewport.ts +11 -12
- package/src/testing/decorators/withVariants.tsx +4 -4
- package/src/util/ThemedClassName.ts +1 -1
- package/dist/types/src/playground/Surfaces.stories.d.ts +0 -21
- package/dist/types/src/playground/Surfaces.stories.d.ts.map +0 -1
- package/src/playground/Surfaces.stories.tsx +0 -73
|
@@ -1,46 +1,35 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
|
+
import React from 'react';
|
|
4
5
|
|
|
6
|
+
import { hueTokenThemes } from '@dxos/react-ui-theme';
|
|
5
7
|
import '@dxos-theme';
|
|
8
|
+
import { type ChromaticPalette, type MessageValence } from '@dxos/react-ui-types';
|
|
6
9
|
|
|
7
10
|
import { Tag } from './Tag';
|
|
8
11
|
import { withTheme } from '../../testing';
|
|
9
12
|
|
|
13
|
+
const palettes = ['neutral', 'success', 'info', 'warning', 'error', ...Object.keys(hueTokenThemes)] as (
|
|
14
|
+
| ChromaticPalette
|
|
15
|
+
| MessageValence
|
|
16
|
+
)[];
|
|
17
|
+
|
|
10
18
|
export default {
|
|
11
19
|
title: 'ui/react-ui-core/Tag',
|
|
12
20
|
component: Tag,
|
|
13
21
|
decorators: [withTheme],
|
|
14
22
|
parameters: { chromatic: { disableSnapshot: false } },
|
|
15
|
-
|
|
16
|
-
palette: {
|
|
17
|
-
control: 'select',
|
|
18
|
-
options: [
|
|
19
|
-
'neutral',
|
|
20
|
-
'success',
|
|
21
|
-
'info',
|
|
22
|
-
'warning',
|
|
23
|
-
'error',
|
|
24
|
-
'red',
|
|
25
|
-
'orange',
|
|
26
|
-
'amber',
|
|
27
|
-
'yellow',
|
|
28
|
-
'lime',
|
|
29
|
-
'green',
|
|
30
|
-
'emerald',
|
|
31
|
-
'teal',
|
|
32
|
-
'cyan',
|
|
33
|
-
'sky',
|
|
34
|
-
'blue',
|
|
35
|
-
'indigo',
|
|
36
|
-
'violet',
|
|
37
|
-
'purple',
|
|
38
|
-
'fuchsia',
|
|
39
|
-
'pink',
|
|
40
|
-
'rose',
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
} as any;
|
|
23
|
+
} as const;
|
|
45
24
|
|
|
46
|
-
export const Default = {
|
|
25
|
+
export const Default = {
|
|
26
|
+
render: () => (
|
|
27
|
+
<div role='grid' className='grid grid-cols-5 gap-2 max-is-screen-md'>
|
|
28
|
+
{palettes.map((palette) => (
|
|
29
|
+
<Tag key={palette} palette={palette}>
|
|
30
|
+
{palette}
|
|
31
|
+
</Tag>
|
|
32
|
+
))}
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Primitive } from '@radix-ui/react-primitive';
|
|
@@ -16,8 +16,17 @@ export type TagProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.sp
|
|
|
16
16
|
asChild?: boolean;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export const Tag = forwardRef<HTMLSpanElement, TagProps>(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
export const Tag = forwardRef<HTMLSpanElement, TagProps>(
|
|
20
|
+
({ asChild, palette = 'neutral', classNames, ...props }, forwardedRef) => {
|
|
21
|
+
const { tx } = useThemeContext();
|
|
22
|
+
const Root = asChild ? Slot : Primitive.span;
|
|
23
|
+
return (
|
|
24
|
+
<Root
|
|
25
|
+
{...props}
|
|
26
|
+
className={tx('tag.root', 'dx-tag', { palette }, classNames)}
|
|
27
|
+
data-hue={palette}
|
|
28
|
+
ref={forwardedRef}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
},
|
|
32
|
+
);
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { createKeyborg } from 'keyborg';
|
|
6
|
-
import React, { createContext, type PropsWithChildren, useEffect } from 'react';
|
|
6
|
+
import React, { createContext, type PropsWithChildren, useEffect, useMemo } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type Density, type Elevation, type ThemeFunction } from '@dxos/react-ui-types';
|
|
9
9
|
|
|
10
10
|
import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider';
|
|
11
|
+
import { type SafeAreaPadding, useSafeArea } from '../../hooks';
|
|
11
12
|
import { hasIosKeyboard } from '../../util';
|
|
12
13
|
import { DensityProvider } from '../DensityProvider';
|
|
13
14
|
import { ElevationProvider } from '../ElevationProvider';
|
|
@@ -18,6 +19,7 @@ export type ThemeContextValue = {
|
|
|
18
19
|
tx: ThemeFunction<any>;
|
|
19
20
|
themeMode: ThemeMode;
|
|
20
21
|
hasIosKeyboard: boolean;
|
|
22
|
+
safeAreaPadding?: SafeAreaPadding;
|
|
21
23
|
noCache?: boolean;
|
|
22
24
|
};
|
|
23
25
|
|
|
@@ -27,7 +29,7 @@ export type ThemeContextValue = {
|
|
|
27
29
|
export const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
|
|
28
30
|
|
|
29
31
|
export type ThemeProviderProps = Omit<TranslationsProviderProps, 'children'> &
|
|
30
|
-
Partial<ThemeContextValue
|
|
32
|
+
Partial<Omit<ThemeContextValue, 'safeAreaPadding'>> &
|
|
31
33
|
PropsWithChildren<{
|
|
32
34
|
rootDensity?: Density;
|
|
33
35
|
rootElevation?: Elevation;
|
|
@@ -41,7 +43,6 @@ export const ThemeProvider = ({
|
|
|
41
43
|
tx = (_path, defaultClassName, _styleProps, ..._options) => defaultClassName,
|
|
42
44
|
themeMode = 'dark',
|
|
43
45
|
rootDensity = 'fine',
|
|
44
|
-
rootElevation = 'base',
|
|
45
46
|
...rest
|
|
46
47
|
}: ThemeProviderProps) => {
|
|
47
48
|
useEffect(() => {
|
|
@@ -52,8 +53,15 @@ export const ThemeProvider = ({
|
|
|
52
53
|
}
|
|
53
54
|
}, []);
|
|
54
55
|
|
|
56
|
+
const safeAreaPadding = useSafeArea();
|
|
57
|
+
|
|
58
|
+
const contextValue = useMemo(
|
|
59
|
+
() => ({ tx, themeMode, hasIosKeyboard: hasIosKeyboard(), safeAreaPadding, ...rest }),
|
|
60
|
+
[tx, themeMode, safeAreaPadding, rest],
|
|
61
|
+
);
|
|
62
|
+
|
|
55
63
|
return (
|
|
56
|
-
<ThemeContext.Provider value={
|
|
64
|
+
<ThemeContext.Provider value={contextValue}>
|
|
57
65
|
<TranslationsProvider
|
|
58
66
|
{...{
|
|
59
67
|
fallback,
|
|
@@ -61,7 +69,7 @@ export const ThemeProvider = ({
|
|
|
61
69
|
appNs,
|
|
62
70
|
}}
|
|
63
71
|
>
|
|
64
|
-
<ElevationProvider elevation=
|
|
72
|
+
<ElevationProvider elevation='base'>
|
|
65
73
|
<DensityProvider density={rootDensity}>{children}</DensityProvider>
|
|
66
74
|
</ElevationProvider>
|
|
67
75
|
</TranslationsProvider>
|
|
@@ -45,7 +45,7 @@ const ToastRoot = forwardRef<HTMLLIElement, ToastRootProps>(({ classNames, child
|
|
|
45
45
|
const { tx } = useThemeContext();
|
|
46
46
|
return (
|
|
47
47
|
<ToastRootPrimitive {...props} className={tx('toast.root', 'toast', {}, classNames)} ref={forwardedRef}>
|
|
48
|
-
<ElevationProvider elevation='
|
|
48
|
+
<ElevationProvider elevation='toast'>{children}</ElevationProvider>
|
|
49
49
|
</ToastRootPrimitive>
|
|
50
50
|
);
|
|
51
51
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type { ToggleGroupItemProps as ToggleGroupItemPrimitiveProps } from '@radix-ui/react-toggle-group';
|
|
5
6
|
import * as ToolbarPrimitive from '@radix-ui/react-toolbar';
|
|
6
7
|
import React, { forwardRef } from 'react';
|
|
7
8
|
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
Toggle,
|
|
16
17
|
type ToggleGroupItemProps,
|
|
17
18
|
type ToggleProps,
|
|
19
|
+
IconButton,
|
|
20
|
+
type IconButtonProps,
|
|
18
21
|
} from '../Buttons';
|
|
19
22
|
import { Link, type LinkProps } from '../Link';
|
|
20
23
|
import { Separator, type SeparatorProps } from '../Separator';
|
|
@@ -40,6 +43,16 @@ const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>((props,
|
|
|
40
43
|
);
|
|
41
44
|
});
|
|
42
45
|
|
|
46
|
+
type ToolbarIconButtonProps = IconButtonProps;
|
|
47
|
+
|
|
48
|
+
const ToolbarIconButton = forwardRef<HTMLButtonElement, ToolbarIconButtonProps>((props, forwardedRef) => {
|
|
49
|
+
return (
|
|
50
|
+
<ToolbarPrimitive.Button asChild>
|
|
51
|
+
<IconButton {...props} ref={forwardedRef} />
|
|
52
|
+
</ToolbarPrimitive.Button>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
43
56
|
type ToolbarToggleProps = ToggleProps;
|
|
44
57
|
|
|
45
58
|
const ToolbarToggle = forwardRef<HTMLButtonElement, ToolbarToggleProps>((props, forwardedRef) => {
|
|
@@ -88,35 +101,52 @@ const ToolbarToggleGroupItem = forwardRef<HTMLButtonElement, ToolbarToggleGroupI
|
|
|
88
101
|
},
|
|
89
102
|
);
|
|
90
103
|
|
|
91
|
-
type
|
|
104
|
+
type ToolbarToggleGroupIconItemProps = Omit<ToggleGroupItemPrimitiveProps, 'className'> & IconButtonProps;
|
|
92
105
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
const ToolbarToggleGroupIconItem = forwardRef<HTMLButtonElement, ToolbarToggleGroupIconItemProps>(
|
|
107
|
+
({ variant, density, elevation, classNames, icon, label, iconOnly, ...props }, forwardedRef) => {
|
|
108
|
+
return (
|
|
109
|
+
<ToolbarPrimitive.ToolbarToggleItem {...props} asChild>
|
|
110
|
+
<IconButton {...{ variant, density, elevation, classNames, icon, label, iconOnly }} ref={forwardedRef} />
|
|
111
|
+
</ToolbarPrimitive.ToolbarToggleItem>
|
|
112
|
+
);
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
type ToolbarSeparatorProps = SeparatorProps & { variant?: 'gap' | 'line' };
|
|
100
117
|
|
|
101
|
-
const
|
|
118
|
+
const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
|
|
119
|
+
({ variant = 'line', ...props }, forwardedRef) => {
|
|
120
|
+
return variant === 'line' ? (
|
|
121
|
+
<ToolbarPrimitive.Separator asChild>
|
|
122
|
+
<Separator {...props} ref={forwardedRef} />
|
|
123
|
+
</ToolbarPrimitive.Separator>
|
|
124
|
+
) : (
|
|
125
|
+
<ToolbarPrimitive.Separator className='grow' ref={forwardedRef} />
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
);
|
|
102
129
|
|
|
103
130
|
export const Toolbar = {
|
|
104
131
|
Root: ToolbarRoot,
|
|
105
132
|
Button: ToolbarButton,
|
|
133
|
+
IconButton: ToolbarIconButton,
|
|
106
134
|
Link: ToolbarLink,
|
|
107
135
|
Toggle: ToolbarToggle,
|
|
108
136
|
ToggleGroup: ToolbarToggleGroup,
|
|
109
137
|
ToggleGroupItem: ToolbarToggleGroupItem,
|
|
138
|
+
ToggleGroupIconItem: ToolbarToggleGroupIconItem,
|
|
110
139
|
Separator: ToolbarSeparator,
|
|
111
|
-
Expander: ToolbarExpander,
|
|
112
140
|
};
|
|
113
141
|
|
|
114
142
|
export type {
|
|
115
143
|
ToolbarRootProps,
|
|
116
144
|
ToolbarButtonProps,
|
|
145
|
+
ToolbarIconButtonProps,
|
|
117
146
|
ToolbarLinkProps,
|
|
118
147
|
ToolbarToggleProps,
|
|
119
148
|
ToolbarToggleGroupProps,
|
|
120
149
|
ToolbarToggleGroupItemProps,
|
|
150
|
+
ToolbarToggleGroupIconItemProps,
|
|
121
151
|
ToolbarSeparatorProps,
|
|
122
152
|
};
|
|
@@ -12,11 +12,12 @@ import { Button } from '../Buttons';
|
|
|
12
12
|
|
|
13
13
|
type StoryTooltipProps = {
|
|
14
14
|
content: string;
|
|
15
|
+
defaultOpen?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
|
-
const StoryTooltip = ({ content }: StoryTooltipProps) => (
|
|
18
|
+
const StoryTooltip = ({ content, defaultOpen }: StoryTooltipProps) => (
|
|
18
19
|
<Tooltip.Provider>
|
|
19
|
-
<Tooltip.Root defaultOpen>
|
|
20
|
+
<Tooltip.Root defaultOpen={defaultOpen}>
|
|
20
21
|
<Tooltip.Trigger asChild>
|
|
21
22
|
<Button>Trigger tooltip</Button>
|
|
22
23
|
</Tooltip.Trigger>
|
|
@@ -44,3 +45,13 @@ export const Default = {
|
|
|
44
45
|
chromatic: { delay: 500 },
|
|
45
46
|
},
|
|
46
47
|
};
|
|
48
|
+
|
|
49
|
+
export const Testing = {
|
|
50
|
+
args: {
|
|
51
|
+
defaultOption: true,
|
|
52
|
+
content: 'This is the tooltip content',
|
|
53
|
+
},
|
|
54
|
+
parameters: {
|
|
55
|
+
chromatic: { delay: 500 },
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
} from '@radix-ui/react-tooltip';
|
|
19
19
|
import React, { forwardRef, type FunctionComponent } from 'react';
|
|
20
20
|
|
|
21
|
-
import { useThemeContext } from '../../hooks';
|
|
21
|
+
import { useElevationContext, useThemeContext } from '../../hooks';
|
|
22
|
+
import { useSafeCollisionPadding } from '../../hooks/useSafeCollisionPadding';
|
|
22
23
|
import { type ThemedClassName } from '../../util';
|
|
23
24
|
|
|
24
25
|
type TooltipProviderProps = TooltipProviderPrimitiveProps;
|
|
@@ -52,18 +53,22 @@ const TooltipArrow = forwardRef<SVGSVGElement, TooltipArrowProps>(({ classNames,
|
|
|
52
53
|
|
|
53
54
|
type TooltipContentProps = ThemedClassName<TooltipContentPrimitiveProps>;
|
|
54
55
|
|
|
55
|
-
const TooltipContent = forwardRef<HTMLDivElement, TooltipContentProps>(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
56
|
+
const TooltipContent = forwardRef<HTMLDivElement, TooltipContentProps>(
|
|
57
|
+
({ classNames, collisionPadding = 8, ...props }, forwardedRef) => {
|
|
58
|
+
const { tx } = useThemeContext();
|
|
59
|
+
const elevation = useElevationContext();
|
|
60
|
+
const safeCollisionPadding = useSafeCollisionPadding(collisionPadding);
|
|
61
|
+
return (
|
|
62
|
+
<TooltipContentPrimitive
|
|
63
|
+
sideOffset={4}
|
|
64
|
+
{...props}
|
|
65
|
+
collisionPadding={safeCollisionPadding}
|
|
66
|
+
className={tx('tooltip.content', 'tooltip', { elevation }, classNames)}
|
|
67
|
+
ref={forwardedRef}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
);
|
|
67
72
|
|
|
68
73
|
export const Tooltip = {
|
|
69
74
|
Provider: TooltipProvider,
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useCallback, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { useResize } from '@dxos/react-hooks';
|
|
8
|
+
|
|
9
|
+
export type SafeAreaPadding = Record<'top' | 'right' | 'bottom' | 'left', number>;
|
|
10
|
+
|
|
11
|
+
export const initialSafeArea = { top: NaN, right: NaN, bottom: NaN, left: NaN };
|
|
12
|
+
|
|
13
|
+
export const useSafeArea = (): SafeAreaPadding => {
|
|
14
|
+
const [padding, setPadding] = useState<SafeAreaPadding>(initialSafeArea);
|
|
15
|
+
const handleResize = useCallback(() => {
|
|
16
|
+
setPadding({
|
|
17
|
+
top: parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-top')),
|
|
18
|
+
right: parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-right')),
|
|
19
|
+
bottom: parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-bottom')),
|
|
20
|
+
left: parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-left')),
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
useResize(handleResize);
|
|
24
|
+
return padding;
|
|
25
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type TooltipContentProps } from '@radix-ui/react-tooltip';
|
|
6
|
+
import { useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { type SafeAreaPadding } from './useSafeArea';
|
|
9
|
+
import { useThemeContext } from './useThemeContext';
|
|
10
|
+
|
|
11
|
+
type PaddingProp = TooltipContentProps['collisionPadding'];
|
|
12
|
+
type PaddingRecord = Exclude<PaddingProp, number | undefined>;
|
|
13
|
+
|
|
14
|
+
const propIsNumber = (prop: PaddingProp): prop is number => Number.isFinite(prop);
|
|
15
|
+
const propsIsRecord = (prop: PaddingProp): prop is PaddingRecord => !!(prop && typeof prop === 'object');
|
|
16
|
+
|
|
17
|
+
const safePadding = (
|
|
18
|
+
propsPadding: TooltipContentProps['collisionPadding'],
|
|
19
|
+
safePadding: SafeAreaPadding,
|
|
20
|
+
side: keyof SafeAreaPadding,
|
|
21
|
+
) => {
|
|
22
|
+
return (
|
|
23
|
+
(propIsNumber(safePadding[side]) ? safePadding[side] : 0) +
|
|
24
|
+
(propIsNumber(propsPadding) ? propsPadding : propsIsRecord(propsPadding) ? propsPadding[side] ?? 0 : 0)
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const useSafeCollisionPadding = (collisionPadding?: PaddingProp) => {
|
|
29
|
+
const { safeAreaPadding } = useThemeContext();
|
|
30
|
+
return useMemo(
|
|
31
|
+
() => ({
|
|
32
|
+
top: safePadding(collisionPadding, safeAreaPadding!, 'top'),
|
|
33
|
+
right: safePadding(collisionPadding, safeAreaPadding!, 'right'),
|
|
34
|
+
bottom: safePadding(collisionPadding, safeAreaPadding!, 'bottom'),
|
|
35
|
+
left: safePadding(collisionPadding, safeAreaPadding!, 'left'),
|
|
36
|
+
}),
|
|
37
|
+
[collisionPadding, safeAreaPadding],
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { useEffect, useState } from 'react';
|
|
5
|
+
import { useCallback, type useEffect, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { useResize } from '@dxos/react-hooks';
|
|
6
8
|
|
|
7
9
|
export const useVisualViewport = (deps?: Parameters<typeof useEffect>[1]) => {
|
|
8
10
|
const [width, setWidth] = useState<number | null>(null);
|
|
9
11
|
const [height, setHeight] = useState<number | null>(null);
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
handleResize();
|
|
20
|
-
return () => window.visualViewport?.removeEventListener('resize', handleResize);
|
|
21
|
-
}, deps ?? []);
|
|
13
|
+
const handleResize = useCallback(() => {
|
|
14
|
+
if (window.visualViewport) {
|
|
15
|
+
setWidth(window.visualViewport.width);
|
|
16
|
+
setHeight(window.visualViewport.height);
|
|
17
|
+
}
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
useResize(handleResize);
|
|
22
21
|
|
|
23
22
|
return { width, height };
|
|
24
23
|
};
|
|
@@ -7,7 +7,7 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Decorator } from '@storybook/react';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
|
|
10
|
-
import { modalSurface, groupSurface, mx,
|
|
10
|
+
import { modalSurface, groupSurface, mx, surfaceShadow } from '@dxos/react-ui-theme';
|
|
11
11
|
import { type Density, type Elevation } from '@dxos/react-ui-types';
|
|
12
12
|
|
|
13
13
|
import { DensityProvider, ElevationProvider } from '../../components';
|
|
@@ -20,8 +20,8 @@ type Config = {
|
|
|
20
20
|
export const withVariants = ({
|
|
21
21
|
elevations = [
|
|
22
22
|
{ elevation: 'base' },
|
|
23
|
-
{ elevation: '
|
|
24
|
-
{ elevation: '
|
|
23
|
+
{ elevation: 'positioned', surface: groupSurface },
|
|
24
|
+
{ elevation: 'dialog', surface: modalSurface },
|
|
25
25
|
],
|
|
26
26
|
densities = ['coarse', 'fine'],
|
|
27
27
|
}: Config = {}): Decorator => {
|
|
@@ -32,7 +32,7 @@ export const withVariants = ({
|
|
|
32
32
|
<div className='flex flex-col gap-8'>
|
|
33
33
|
{densities.map((density) => (
|
|
34
34
|
<DensityProvider key={density} density={density}>
|
|
35
|
-
<div className={mx('p-4 rounded-lg', surface,
|
|
35
|
+
<div className={mx('p-4 rounded-lg', surface, surfaceShadow({ elevation }))}>
|
|
36
36
|
<Story />
|
|
37
37
|
</div>
|
|
38
38
|
</DensityProvider>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import '@dxos-theme';
|
|
2
|
-
import React, { type PropsWithChildren } from 'react';
|
|
3
|
-
type SurfaceLevel = 'base' | 'group' | 'chrome' | 'fixed' | 'input' | 'accent';
|
|
4
|
-
declare const _default: {
|
|
5
|
-
title: string;
|
|
6
|
-
component: ({ children, level }: PropsWithChildren & {
|
|
7
|
-
level: SurfaceLevel;
|
|
8
|
-
}) => React.JSX.Element;
|
|
9
|
-
render: () => React.JSX.Element;
|
|
10
|
-
decorators: import("@storybook/react/*").Decorator[];
|
|
11
|
-
parameters: {
|
|
12
|
-
chromatic: {
|
|
13
|
-
disableSnapshot: boolean;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
export default _default;
|
|
18
|
-
export declare const Default: {
|
|
19
|
-
args: {};
|
|
20
|
-
};
|
|
21
|
-
//# sourceMappingURL=Surfaces.stories.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Surfaces.stories.d.ts","sourceRoot":"","sources":["../../../../src/playground/Surfaces.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAgBtD,KAAK,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;;;qCAEzC,iBAAiB,GAAG;QAAE,KAAK,EAAE,YAAY,CAAA;KAAE;;;;;;;;;AAsCjF,wBAME;AAEF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
|
-
import React, { type PropsWithChildren } from 'react';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
baseSurface,
|
|
11
|
-
modalSurface,
|
|
12
|
-
groupSurface,
|
|
13
|
-
mx,
|
|
14
|
-
surfaceElevation,
|
|
15
|
-
fixedSurface,
|
|
16
|
-
fixedBorder,
|
|
17
|
-
attentionSurface,
|
|
18
|
-
accentSurface,
|
|
19
|
-
} from '@dxos/react-ui-theme';
|
|
20
|
-
|
|
21
|
-
import { withTheme } from '../testing';
|
|
22
|
-
|
|
23
|
-
type SurfaceLevel = 'base' | 'group' | 'chrome' | 'fixed' | 'input' | 'accent';
|
|
24
|
-
|
|
25
|
-
const Surface = ({ children, level }: PropsWithChildren & { level: SurfaceLevel }) => {
|
|
26
|
-
const surface =
|
|
27
|
-
level === 'chrome'
|
|
28
|
-
? [modalSurface, surfaceElevation({ elevation: 'chrome' })]
|
|
29
|
-
: level === 'group'
|
|
30
|
-
? [groupSurface, surfaceElevation({ elevation: 'group' })]
|
|
31
|
-
: level === 'input'
|
|
32
|
-
? [attentionSurface, surfaceElevation({ elevation: 'group' })]
|
|
33
|
-
: level === 'fixed'
|
|
34
|
-
? [fixedSurface, fixedBorder, 'border', surfaceElevation({ elevation: 'chrome' })]
|
|
35
|
-
: level === 'accent'
|
|
36
|
-
? [accentSurface, surfaceElevation({ elevation: 'chrome' })]
|
|
37
|
-
: [baseSurface];
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<div
|
|
41
|
-
role='region'
|
|
42
|
-
className={mx('flex justify-center items-center m-8 p-2 w-[320px] h-[160px] rounded-lg', ...surface)}
|
|
43
|
-
>
|
|
44
|
-
<div>{level}</div>
|
|
45
|
-
{children}
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const SurfaceStory = () => {
|
|
51
|
-
return (
|
|
52
|
-
<div className='bg-cubes p-10 m-0'>
|
|
53
|
-
<Surface level='fixed' />
|
|
54
|
-
<Surface level='base' />
|
|
55
|
-
<Surface level='group' />
|
|
56
|
-
<Surface level='chrome' />
|
|
57
|
-
<Surface level='input' />
|
|
58
|
-
<Surface level='accent' />
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export default {
|
|
64
|
-
title: 'ui/react-ui-core/Playground/Surfaces',
|
|
65
|
-
component: Surface,
|
|
66
|
-
render: SurfaceStory,
|
|
67
|
-
decorators: [withTheme],
|
|
68
|
-
parameters: { chromatic: { disableSnapshot: false } },
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const Default = {
|
|
72
|
-
args: {},
|
|
73
|
-
};
|