@dxos/react-ui 0.8.4-main.66e292d → 0.8.4-main.69d29f4
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-CEKVHJ27.mjs +774 -0
- package/dist/lib/browser/chunk-CEKVHJ27.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +3065 -66
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +31 -43
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2NHEX4AD.mjs +776 -0
- package/dist/lib/node-esm/chunk-2NHEX4AD.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +3065 -66
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +31 -43
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/components/Button/Button.d.ts +1 -1
- package/dist/types/src/components/Button/Button.d.ts.map +1 -1
- package/dist/types/src/components/Button/IconButton.d.ts +2 -1
- package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
- package/dist/types/src/components/Button/ToggleGroup.d.ts +4 -4
- package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +4 -4
- package/dist/types/src/components/DensityProvider/DensityProvider.d.ts +1 -1
- package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.d.ts +18 -9
- package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts +7 -5
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts +1 -1
- package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
- package/dist/types/src/components/Icon/Icon.d.ts +1 -1
- package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.d.ts +5 -2
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts +1 -1
- package/dist/types/src/components/List/List.d.ts.map +1 -1
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/{Menus → Menu}/ContextMenu.d.ts +6 -6
- package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -0
- package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/{Menus → Menu}/DropdownMenu.d.ts +1 -1
- package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -0
- package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/Menu/index.d.ts.map +1 -0
- package/dist/types/src/components/Message/Message.d.ts +1 -1
- package/dist/types/src/components/Message/Message.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.stories.d.ts +1 -1
- package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +9 -7
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +4 -0
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +4 -2
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +2 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.d.ts +9 -9
- package/dist/types/src/components/Separator/Separator.d.ts +1 -1
- package/dist/types/src/components/Tag/Tag.d.ts +1 -1
- package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -2
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -8
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts +2 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/Toast/Toast.d.ts +4 -4
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +10 -10
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useDensityContext.d.ts +1 -1
- package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useElevationContext.d.ts +1 -1
- package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayout.d.ts +3 -3
- package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayoutVariants.d.ts +1 -1
- package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -2
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -26
- package/src/components/Avatars/Avatar.stories.tsx +2 -2
- package/src/components/Avatars/Avatar.tsx +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Button/IconButton.tsx +8 -3
- package/src/components/Clipboard/CopyButton.tsx +3 -3
- package/src/components/DensityProvider/DensityProvider.tsx +1 -1
- package/src/components/Dialog/Dialog.stories.tsx +47 -17
- package/src/components/Dialog/Dialog.tsx +140 -40
- package/src/components/ElevationProvider/ElevationProvider.tsx +1 -1
- package/src/components/Icon/Icon.stories.tsx +1 -1
- package/src/components/Icon/Icon.tsx +1 -1
- package/src/components/Input/Input.stories.tsx +2 -2
- package/src/components/Input/Input.tsx +13 -4
- package/src/components/List/List.stories.tsx +16 -12
- package/src/components/List/List.tsx +1 -1
- package/src/components/{Menus → Menu}/DropdownMenu.tsx +57 -55
- package/src/components/Message/Message.stories.tsx +1 -1
- package/src/components/Message/Message.tsx +30 -5
- package/src/components/Popover/Popover.tsx +35 -33
- package/src/components/ScrollArea/ScrollArea.stories.tsx +53 -3
- package/src/components/ScrollArea/ScrollArea.tsx +50 -4
- package/src/components/ScrollContainer/ScrollContainer.stories.tsx +2 -1
- package/src/components/ScrollContainer/ScrollContainer.tsx +90 -88
- package/src/components/Tag/Tag.stories.tsx +2 -2
- package/src/components/Tag/Tag.tsx +1 -1
- package/src/components/ThemeProvider/ThemeProvider.tsx +1 -3
- package/src/components/ThemeProvider/TranslationsProvider.tsx +1 -16
- package/src/components/ThemeProvider/index.ts +3 -3
- package/src/components/Toolbar/Toolbar.tsx +23 -8
- package/src/components/Tooltip/Tooltip.tsx +22 -20
- package/src/components/index.ts +1 -1
- package/src/hooks/useDensityContext.ts +1 -1
- package/src/hooks/useElevationContext.ts +1 -1
- package/src/index.ts +1 -1
- package/src/testing/decorators/withLayout.tsx +22 -15
- package/src/testing/decorators/withLayoutVariants.tsx +3 -3
- package/src/testing/decorators/withTheme.tsx +3 -2
- package/src/util/index.ts +2 -2
- package/dist/lib/browser/chunk-N5GDJTT2.mjs +0 -4707
- package/dist/lib/browser/chunk-N5GDJTT2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SP7VQH72.mjs +0 -4709
- package/dist/lib/node-esm/chunk-SP7VQH72.mjs.map +0 -7
- package/dist/types/src/components/Menus/ContextMenu.d.ts.map +0 -1
- package/dist/types/src/components/Menus/ContextMenu.stories.d.ts.map +0 -1
- package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +0 -1
- package/dist/types/src/components/Menus/DropdownMenu.stories.d.ts.map +0 -1
- package/dist/types/src/components/Menus/index.d.ts.map +0 -1
- package/dist/types/src/util/ThemedClassName.d.ts +0 -5
- package/dist/types/src/util/ThemedClassName.d.ts.map +0 -1
- package/dist/types/src/util/domino.d.ts +0 -18
- package/dist/types/src/util/domino.d.ts.map +0 -1
- package/src/util/ThemedClassName.ts +0 -7
- package/src/util/domino.ts +0 -53
- /package/dist/types/src/components/{Menus → Menu}/ContextMenu.stories.d.ts +0 -0
- /package/dist/types/src/components/{Menus → Menu}/DropdownMenu.stories.d.ts +0 -0
- /package/dist/types/src/components/{Menus → Menu}/index.d.ts +0 -0
- /package/src/components/{Menus → Menu}/ContextMenu.stories.tsx +0 -0
- /package/src/components/{Menus → Menu}/ContextMenu.tsx +0 -0
- /package/src/components/{Menus → Menu}/DropdownMenu.stories.tsx +0 -0
- /package/src/components/{Menus → Menu}/index.ts +0 -0
|
@@ -14,18 +14,21 @@ import {
|
|
|
14
14
|
Viewport as ScrollAreaPrimitiveViewport,
|
|
15
15
|
type ScrollAreaViewportProps as ScrollAreaPrimitiveViewportProps,
|
|
16
16
|
} from '@radix-ui/react-scroll-area';
|
|
17
|
-
import React, { forwardRef } from 'react';
|
|
17
|
+
import React, { type PropsWithChildren, forwardRef } from 'react';
|
|
18
|
+
|
|
19
|
+
import { mx } from '@dxos/ui-theme';
|
|
18
20
|
|
|
19
21
|
import { useThemeContext } from '../../hooks';
|
|
20
22
|
import { type ThemedClassName } from '../../util';
|
|
21
23
|
|
|
22
24
|
type ScrollAreaVariant = 'coarse' | 'fine';
|
|
23
25
|
|
|
26
|
+
//
|
|
27
|
+
// Root
|
|
28
|
+
//
|
|
29
|
+
|
|
24
30
|
type ScrollAreaRootProps = ThemedClassName<ScrollAreaPrimitiveRootProps>;
|
|
25
31
|
|
|
26
|
-
/**
|
|
27
|
-
* @deprecated
|
|
28
|
-
*/
|
|
29
32
|
const ScrollAreaRoot = forwardRef<HTMLDivElement, ScrollAreaRootProps>(({ classNames, ...props }, forwardedRef) => {
|
|
30
33
|
const { tx } = useThemeContext();
|
|
31
34
|
return (
|
|
@@ -37,6 +40,10 @@ const ScrollAreaRoot = forwardRef<HTMLDivElement, ScrollAreaRootProps>(({ classN
|
|
|
37
40
|
);
|
|
38
41
|
});
|
|
39
42
|
|
|
43
|
+
//
|
|
44
|
+
// Viewport
|
|
45
|
+
//
|
|
46
|
+
|
|
40
47
|
type ScrollAreaViewportProps = ThemedClassName<ScrollAreaPrimitiveViewportProps>;
|
|
41
48
|
|
|
42
49
|
const ScrollAreaViewport = forwardRef<HTMLDivElement, ScrollAreaViewportProps>(
|
|
@@ -52,6 +59,10 @@ const ScrollAreaViewport = forwardRef<HTMLDivElement, ScrollAreaViewportProps>(
|
|
|
52
59
|
},
|
|
53
60
|
);
|
|
54
61
|
|
|
62
|
+
//
|
|
63
|
+
// Scrollbar
|
|
64
|
+
//
|
|
65
|
+
|
|
55
66
|
type ScrollAreaScrollbarProps = ThemedClassName<ScrollAreaPrimitiveScrollbarProps> & { variant?: ScrollAreaVariant };
|
|
56
67
|
|
|
57
68
|
const ScrollAreaScrollbar = forwardRef<HTMLDivElement, ScrollAreaScrollbarProps>(
|
|
@@ -68,6 +79,10 @@ const ScrollAreaScrollbar = forwardRef<HTMLDivElement, ScrollAreaScrollbarProps>
|
|
|
68
79
|
},
|
|
69
80
|
);
|
|
70
81
|
|
|
82
|
+
//
|
|
83
|
+
// Thumb
|
|
84
|
+
//
|
|
85
|
+
|
|
71
86
|
type ScrollAreaThumbProps = ThemedClassName<ScrollAreaPrimitiveThumbProps>;
|
|
72
87
|
|
|
73
88
|
const ScrollAreaThumb = forwardRef<HTMLDivElement, ScrollAreaThumbProps>(({ classNames, ...props }, forwardedRef) => {
|
|
@@ -81,6 +96,10 @@ const ScrollAreaThumb = forwardRef<HTMLDivElement, ScrollAreaThumbProps>(({ clas
|
|
|
81
96
|
);
|
|
82
97
|
});
|
|
83
98
|
|
|
99
|
+
//
|
|
100
|
+
// Corner
|
|
101
|
+
//
|
|
102
|
+
|
|
84
103
|
type ScrollAreaCornerProps = ThemedClassName<ScrollAreaPrimitiveCornerProps>;
|
|
85
104
|
|
|
86
105
|
const ScrollAreaCorner = forwardRef<HTMLDivElement, ScrollAreaCornerProps>(({ classNames, ...props }, forwardedRef) => {
|
|
@@ -94,12 +113,38 @@ const ScrollAreaCorner = forwardRef<HTMLDivElement, ScrollAreaCornerProps>(({ cl
|
|
|
94
113
|
);
|
|
95
114
|
});
|
|
96
115
|
|
|
116
|
+
//
|
|
117
|
+
// Expander
|
|
118
|
+
//
|
|
119
|
+
|
|
120
|
+
type ScrollAreaExpanderProps = ThemedClassName<PropsWithChildren>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Size-locking wrapper required for inner ScrollArea to function correctly.
|
|
124
|
+
* NOTE: Radix ScrollArea.Viewport applies `display: table` to its immediate child,
|
|
125
|
+
* causing the content to participate in table layout and escape the intended fixed-size viewport.
|
|
126
|
+
*/
|
|
127
|
+
const ScrollAreaExpander = ({ classNames, children }: ScrollAreaExpanderProps) => {
|
|
128
|
+
return (
|
|
129
|
+
<div role='none' className={mx('relative bs-full is-full overflow-hidden', classNames)}>
|
|
130
|
+
<div role='none' className='absolute inset-0 overflow-hidden'>
|
|
131
|
+
{children}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
//
|
|
138
|
+
// ScrollArea
|
|
139
|
+
//
|
|
140
|
+
|
|
97
141
|
export const ScrollArea = {
|
|
98
142
|
Root: ScrollAreaRoot,
|
|
99
143
|
Viewport: ScrollAreaViewport,
|
|
100
144
|
Scrollbar: ScrollAreaScrollbar,
|
|
101
145
|
Thumb: ScrollAreaThumb,
|
|
102
146
|
Corner: ScrollAreaCorner,
|
|
147
|
+
Expander: ScrollAreaExpander,
|
|
103
148
|
};
|
|
104
149
|
|
|
105
150
|
export type {
|
|
@@ -108,4 +153,5 @@ export type {
|
|
|
108
153
|
ScrollAreaScrollbarProps,
|
|
109
154
|
ScrollAreaThumbProps,
|
|
110
155
|
ScrollAreaCornerProps,
|
|
156
|
+
ScrollAreaExpanderProps,
|
|
111
157
|
};
|
|
@@ -45,6 +45,7 @@ const DefaultStory = (props: ScrollContainerRootProps) => {
|
|
|
45
45
|
</div>
|
|
46
46
|
))}
|
|
47
47
|
</ScrollContainer.Viewport>
|
|
48
|
+
<ScrollContainer.ScrollDownButton />
|
|
48
49
|
</ScrollContainer.Root>
|
|
49
50
|
</div>
|
|
50
51
|
);
|
|
@@ -54,7 +55,7 @@ const meta = {
|
|
|
54
55
|
title: 'ui/react-ui-core/ScrollContainer',
|
|
55
56
|
component: ScrollContainer.Root,
|
|
56
57
|
render: DefaultStory,
|
|
57
|
-
decorators: [withTheme, withLayout({
|
|
58
|
+
decorators: [withTheme, withLayout({ layout: 'column', classNames: 'is-[30rem]' })],
|
|
58
59
|
} satisfies Meta<typeof DefaultStory>;
|
|
59
60
|
|
|
60
61
|
export default meta;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { useState } from '@preact-signals/safe-react/react';
|
|
6
5
|
import { createContext } from '@radix-ui/react-context';
|
|
7
6
|
import React, {
|
|
8
7
|
type HTMLAttributes,
|
|
@@ -13,13 +12,14 @@ import React, {
|
|
|
13
12
|
useImperativeHandle,
|
|
14
13
|
useMemo,
|
|
15
14
|
useRef,
|
|
15
|
+
useState,
|
|
16
16
|
} from 'react';
|
|
17
17
|
|
|
18
18
|
// TODO(burdon): Move these deps to @dxos/dom-util.
|
|
19
19
|
import { addEventListener, combine } from '@dxos/async';
|
|
20
20
|
import { invariant } from '@dxos/invariant';
|
|
21
21
|
import { useForwardedRef } from '@dxos/react-hooks';
|
|
22
|
-
import { mx } from '@dxos/
|
|
22
|
+
import { mx } from '@dxos/ui-theme';
|
|
23
23
|
|
|
24
24
|
import { type ThemedClassName } from '../../util';
|
|
25
25
|
import { IconButton } from '../Button';
|
|
@@ -51,98 +51,101 @@ type RootProps = ThemedClassName<
|
|
|
51
51
|
PropsWithChildren<{
|
|
52
52
|
pin?: boolean;
|
|
53
53
|
fade?: boolean;
|
|
54
|
+
behavior?: ScrollBehavior;
|
|
54
55
|
}>
|
|
55
56
|
>;
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Scroll container that automatically scrolls to the bottom when new content is added.
|
|
59
60
|
*/
|
|
60
|
-
const Root = forwardRef<ScrollController, RootProps>(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
const Root = forwardRef<ScrollController, RootProps>(
|
|
62
|
+
({ children, classNames, pin, fade, behavior: behaviorProp = 'smooth' }, forwardedRef) => {
|
|
63
|
+
const scrollerRef = useRef<HTMLDivElement>(null);
|
|
64
|
+
const autoScrollRef = useRef(false);
|
|
65
|
+
const [overflow, setOverflow] = useState(false);
|
|
66
|
+
const [pinned, setPinned] = useState(pin);
|
|
67
|
+
|
|
68
|
+
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
69
|
+
const scrollToBottom = useCallback((behavior: ScrollBehavior = behaviorProp) => {
|
|
70
|
+
if (scrollerRef.current) {
|
|
71
|
+
// Temporarily hide scrollbar to prevent flicker.
|
|
72
|
+
autoScrollRef.current = true;
|
|
73
|
+
scrollerRef.current.classList.add('scrollbar-none');
|
|
74
|
+
scrollerRef.current.scrollTo({
|
|
75
|
+
top: scrollerRef.current.scrollHeight,
|
|
76
|
+
behavior,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
clearTimeout(timeoutRef.current);
|
|
80
|
+
if (behavior !== 'instant') {
|
|
81
|
+
timeoutRef.current = setTimeout(() => {
|
|
82
|
+
scrollerRef.current?.classList.remove('scrollbar-none');
|
|
83
|
+
autoScrollRef.current = false;
|
|
84
|
+
}, 500);
|
|
85
|
+
}
|
|
86
|
+
setPinned(true);
|
|
83
87
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
scrollToBottom('smooth');
|
|
98
|
-
},
|
|
99
|
-
}),
|
|
100
|
-
[scrollToBottom, scrollerRef.current],
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// Scroll controller imperative ref.
|
|
104
|
-
useImperativeHandle(forwardedRef, () => controller, [controller]);
|
|
105
|
-
|
|
106
|
-
// Listen for scroll events.
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (!scrollerRef.current) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return combine(
|
|
113
|
-
// Check if user scrolls.
|
|
114
|
-
addEventListener(scrollerRef.current, 'wheel', () => {
|
|
115
|
-
setPinned(isBottom(scrollerRef.current));
|
|
116
|
-
}),
|
|
117
|
-
// Check if scrolls.
|
|
118
|
-
addEventListener(scrollerRef.current, 'scroll', () => {
|
|
119
|
-
setOverflow((scrollerRef.current?.scrollTop ?? 0) > 0);
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const controller = useMemo(
|
|
91
|
+
() => ({
|
|
92
|
+
viewport: scrollerRef.current,
|
|
93
|
+
scrollToTop: () => {
|
|
94
|
+
invariant(scrollerRef.current);
|
|
95
|
+
scrollerRef.current.scrollTo({ top: 0, behavior: 'smooth' });
|
|
96
|
+
setPinned(false);
|
|
97
|
+
},
|
|
98
|
+
scrollToBottom: () => {
|
|
99
|
+
scrollToBottom('smooth');
|
|
100
|
+
},
|
|
120
101
|
}),
|
|
102
|
+
[scrollToBottom, scrollerRef.current],
|
|
121
103
|
);
|
|
122
|
-
}, []);
|
|
123
104
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
105
|
+
// Scroll controller imperative ref.
|
|
106
|
+
useImperativeHandle(forwardedRef, () => controller, [controller]);
|
|
107
|
+
|
|
108
|
+
// Listen for scroll events.
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!scrollerRef.current) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return combine(
|
|
115
|
+
// Check if user scrolls.
|
|
116
|
+
addEventListener(scrollerRef.current, 'wheel', () => {
|
|
117
|
+
setPinned(isBottom(scrollerRef.current));
|
|
118
|
+
}),
|
|
119
|
+
// Check if scrolls.
|
|
120
|
+
addEventListener(scrollerRef.current, 'scroll', () => {
|
|
121
|
+
setOverflow((scrollerRef.current?.scrollTop ?? 0) > 0);
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
}, []);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<ScrollContainerProvider pinned={pinned} controller={controller} scrollToBottom={scrollToBottom}>
|
|
128
|
+
<div className='relative grid flex-1 min-bs-0 overflow-hidden'>
|
|
129
|
+
{fade && (
|
|
130
|
+
<div
|
|
131
|
+
role='none'
|
|
132
|
+
data-visible={overflow}
|
|
133
|
+
className={mx(
|
|
134
|
+
// NOTE: Gradients may not be visible with dark reader extensions.
|
|
135
|
+
'z-10 absolute block-start-0 inset-inline-0 bs-24 is-full',
|
|
136
|
+
'opacity-0 duration-200 transition-opacity data-[visible="true"]:opacity-100',
|
|
137
|
+
'bg-gradient-to-b from-[--surface-bg] to-transparent pointer-events-none',
|
|
138
|
+
)}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
141
|
+
<div className={mx('flex flex-col min-bs-0 overflow-y-auto scrollbar-thin', classNames)} ref={scrollerRef}>
|
|
142
|
+
{children}
|
|
143
|
+
</div>
|
|
141
144
|
</div>
|
|
142
|
-
</
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
</ScrollContainerProvider>
|
|
146
|
+
);
|
|
147
|
+
},
|
|
148
|
+
);
|
|
146
149
|
|
|
147
150
|
Root.displayName = 'ScrollContainer.Root';
|
|
148
151
|
|
|
@@ -161,14 +164,13 @@ const Viewport = forwardRef<HTMLDivElement, ViewportProps>(({ classNames, childr
|
|
|
161
164
|
return;
|
|
162
165
|
}
|
|
163
166
|
|
|
167
|
+
// Scroll instantly otherwise it might move while we're scrolling.
|
|
168
|
+
scrollToBottom();
|
|
169
|
+
|
|
164
170
|
// Setup resize observer to detect content changes.
|
|
165
171
|
const resizeObserver = new ResizeObserver(() => scrollToBottom());
|
|
166
|
-
scrollToBottom('instant');
|
|
167
|
-
|
|
168
172
|
resizeObserver.observe(contentRef.current);
|
|
169
|
-
return () =>
|
|
170
|
-
resizeObserver.disconnect();
|
|
171
|
-
};
|
|
173
|
+
return () => resizeObserver.disconnect();
|
|
172
174
|
}, [pinned, scrollToBottom]);
|
|
173
175
|
|
|
174
176
|
return (
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import { hues } from '@dxos/
|
|
9
|
-
import { type ChromaticPalette, type MessageValence } from '@dxos/
|
|
8
|
+
import { hues } from '@dxos/ui-theme';
|
|
9
|
+
import { type ChromaticPalette, type MessageValence } from '@dxos/ui-types';
|
|
10
10
|
|
|
11
11
|
import { withTheme } from '../../testing';
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ import { Primitive } from '@radix-ui/react-primitive';
|
|
|
6
6
|
import { Slot } from '@radix-ui/react-slot';
|
|
7
7
|
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
8
8
|
|
|
9
|
-
import { type ChromaticPalette, type MessageValence, type NeutralPalette } from '@dxos/
|
|
9
|
+
import { type ChromaticPalette, type MessageValence, type NeutralPalette } from '@dxos/ui-types';
|
|
10
10
|
|
|
11
11
|
import { useThemeContext } from '../../hooks';
|
|
12
12
|
import { type ThemedClassName } from '../../util';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { createKeyborg } from 'keyborg';
|
|
6
6
|
import React, { type PropsWithChildren, createContext, useEffect, useMemo } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type Density, type Elevation, type ThemeFunction } from '@dxos/
|
|
8
|
+
import { type Density, type Elevation, type ThemeFunction, type ThemeMode } from '@dxos/ui-types';
|
|
9
9
|
|
|
10
10
|
import { type SafeAreaPadding, useSafeArea } from '../../hooks';
|
|
11
11
|
import { hasIosKeyboard } from '../../util';
|
|
@@ -14,8 +14,6 @@ import { ElevationProvider } from '../ElevationProvider';
|
|
|
14
14
|
|
|
15
15
|
import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider';
|
|
16
16
|
|
|
17
|
-
export type ThemeMode = 'dark' | 'light';
|
|
18
|
-
|
|
19
17
|
export type ThemeContextValue = {
|
|
20
18
|
tx: ThemeFunction<any>;
|
|
21
19
|
themeMode: ThemeMode;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Locale, enUS as dtLocaleEnUs } from 'date-fns/locale';
|
|
6
|
-
import i18Next, { type Resource
|
|
6
|
+
import i18Next, { type Resource } from 'i18next';
|
|
7
7
|
import React, { type ReactNode, Suspense, createContext, useContext, useEffect, useState } from 'react';
|
|
8
8
|
import { initReactI18next, useTranslation as useI18NextTranslation } from 'react-i18next';
|
|
9
9
|
|
|
@@ -11,21 +11,6 @@ const initialLng = 'en-US';
|
|
|
11
11
|
const initialNs = 'dxos-common';
|
|
12
12
|
const initialDtLocale = dtLocaleEnUs;
|
|
13
13
|
|
|
14
|
-
// TODO(thure): `Parameters<TFunction>` causes typechecking issues because `TFunction` has so many signatures.
|
|
15
|
-
export type Label = string | [string, { ns: string; count?: number; defaultValue?: string }];
|
|
16
|
-
|
|
17
|
-
export const isLabel = (o: any): o is Label =>
|
|
18
|
-
typeof o === 'string' ||
|
|
19
|
-
(Array.isArray(o) &&
|
|
20
|
-
o.length === 2 &&
|
|
21
|
-
typeof o[0] === 'string' &&
|
|
22
|
-
!!o[1] &&
|
|
23
|
-
typeof o[1] === 'object' &&
|
|
24
|
-
'ns' in o[1] &&
|
|
25
|
-
typeof o[1].ns === 'string');
|
|
26
|
-
|
|
27
|
-
export const toLocalizedString = (label: Label, t: TFunction) => (Array.isArray(label) ? t(...label) : label);
|
|
28
|
-
|
|
29
14
|
export const resources = {
|
|
30
15
|
[initialLng]: {
|
|
31
16
|
[initialNs]: {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
export { type Label, isLabel, toLocalizedString, useTranslation } from './TranslationsProvider';
|
|
5
|
+
export { type Label, isLabel, toLocalizedString } from '@dxos/ui-types';
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
export * from './ThemeProvider';
|
|
8
|
+
export { useTranslation } from './TranslationsProvider';
|
|
@@ -24,18 +24,22 @@ import { Separator, type SeparatorProps } from '../Separator';
|
|
|
24
24
|
|
|
25
25
|
type ToolbarRootProps = ThemedClassName<
|
|
26
26
|
ToolbarPrimitive.ToolbarProps & {
|
|
27
|
-
textBlockWidth?: boolean;
|
|
28
|
-
layoutManaged?: boolean;
|
|
29
27
|
disabled?: boolean;
|
|
28
|
+
layoutManaged?: boolean; // TODO(burdon): Replace with Toolbar.Content to allow inner layout management?
|
|
29
|
+
textBlockWidth?: boolean;
|
|
30
30
|
}
|
|
31
31
|
>;
|
|
32
32
|
|
|
33
|
+
// TODO(burdon): Implement asChild.
|
|
33
34
|
const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
|
|
34
|
-
({ classNames, children, layoutManaged, textBlockWidth:
|
|
35
|
+
({ classNames, children, disabled, layoutManaged, textBlockWidth: textBlockWidthProp, ...props }, forwardedRef) => {
|
|
35
36
|
const { tx } = useThemeContext();
|
|
36
|
-
const InnerRoot =
|
|
37
|
-
const innerRootProps =
|
|
38
|
-
? {
|
|
37
|
+
const InnerRoot = textBlockWidthProp ? 'div' : Fragment;
|
|
38
|
+
const innerRootProps = textBlockWidthProp
|
|
39
|
+
? {
|
|
40
|
+
role: 'none',
|
|
41
|
+
className: tx('toolbar.inner', 'toolbar', { layoutManaged }, classNames),
|
|
42
|
+
}
|
|
39
43
|
: {};
|
|
40
44
|
|
|
41
45
|
return (
|
|
@@ -66,7 +70,7 @@ type ToolbarIconButtonProps = IconButtonProps;
|
|
|
66
70
|
const ToolbarIconButton = forwardRef<HTMLButtonElement, ToolbarIconButtonProps>((props, forwardedRef) => {
|
|
67
71
|
return (
|
|
68
72
|
<ToolbarPrimitive.Button asChild>
|
|
69
|
-
<IconButton {...props} ref={forwardedRef} />
|
|
73
|
+
<IconButton {...props} noTooltip ref={forwardedRef} />
|
|
70
74
|
</ToolbarPrimitive.Button>
|
|
71
75
|
);
|
|
72
76
|
});
|
|
@@ -125,7 +129,18 @@ const ToolbarToggleGroupIconItem = forwardRef<HTMLButtonElement, ToolbarToggleGr
|
|
|
125
129
|
({ variant, density, elevation, classNames, icon, label, iconOnly, ...props }, forwardedRef) => {
|
|
126
130
|
return (
|
|
127
131
|
<ToolbarPrimitive.ToolbarToggleItem {...props} asChild>
|
|
128
|
-
<IconButton
|
|
132
|
+
<IconButton
|
|
133
|
+
{...{
|
|
134
|
+
variant,
|
|
135
|
+
density,
|
|
136
|
+
elevation,
|
|
137
|
+
classNames,
|
|
138
|
+
icon,
|
|
139
|
+
label,
|
|
140
|
+
iconOnly,
|
|
141
|
+
}}
|
|
142
|
+
ref={forwardedRef}
|
|
143
|
+
/>
|
|
129
144
|
</ToolbarPrimitive.ToolbarToggleItem>
|
|
130
145
|
);
|
|
131
146
|
},
|
|
@@ -41,9 +41,9 @@ type TooltipScopedProps<P = {}> = P & { __scopeTooltip?: Scope };
|
|
|
41
41
|
const [createTooltipContext, createTooltipScope] = createContextScope('Tooltip', [createPopperScope]);
|
|
42
42
|
const usePopperScope = createPopperScope();
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
//
|
|
45
|
+
// Tooltip
|
|
46
|
+
//
|
|
47
47
|
|
|
48
48
|
const DEFAULT_DELAY_DURATION = 700;
|
|
49
49
|
const TOOLTIP_OPEN = 'tooltip.open';
|
|
@@ -228,9 +228,9 @@ const TooltipProvider: FC<TooltipProviderProps> = (props: TooltipScopedProps<Too
|
|
|
228
228
|
|
|
229
229
|
TooltipProvider.displayName = TOOLTIP_NAME;
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
//
|
|
232
|
+
// TooltipVirtualTrigger
|
|
233
|
+
//
|
|
234
234
|
|
|
235
235
|
const TooltipVirtualTrigger = ({
|
|
236
236
|
virtualRef,
|
|
@@ -240,9 +240,9 @@ const TooltipVirtualTrigger = ({
|
|
|
240
240
|
return <PopperPrimitive.Anchor asChild {...popperScope} virtualRef={virtualRef} />;
|
|
241
241
|
};
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
//
|
|
244
|
+
// TooltipTrigger
|
|
245
|
+
//
|
|
246
246
|
|
|
247
247
|
const TRIGGER_NAME = 'TooltipTrigger';
|
|
248
248
|
|
|
@@ -322,9 +322,9 @@ const TooltipTrigger = forwardRef<TooltipTriggerElement, TooltipTriggerProps>(
|
|
|
322
322
|
|
|
323
323
|
TooltipTrigger.displayName = TRIGGER_NAME;
|
|
324
324
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
//
|
|
326
|
+
// TooltipPortal
|
|
327
|
+
//
|
|
328
328
|
|
|
329
329
|
const PORTAL_NAME = 'TooltipPortal';
|
|
330
330
|
|
|
@@ -363,9 +363,9 @@ const TooltipPortal: FC<TooltipPortalProps> = (props: TooltipScopedProps<Tooltip
|
|
|
363
363
|
|
|
364
364
|
TooltipPortal.displayName = PORTAL_NAME;
|
|
365
365
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
366
|
+
//
|
|
367
|
+
// TooltipContent
|
|
368
|
+
//
|
|
369
369
|
|
|
370
370
|
const CONTENT_NAME = 'TooltipContent';
|
|
371
371
|
|
|
@@ -574,9 +574,9 @@ const TooltipContentImpl = forwardRef<TooltipContentImplElement, TooltipContentI
|
|
|
574
574
|
|
|
575
575
|
TooltipContent.displayName = CONTENT_NAME;
|
|
576
576
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
577
|
+
//
|
|
578
|
+
// TooltipArrow
|
|
579
|
+
//
|
|
580
580
|
|
|
581
581
|
const ARROW_NAME = 'TooltipArrow';
|
|
582
582
|
|
|
@@ -599,8 +599,6 @@ const TooltipArrow = forwardRef<TooltipArrowElement, TooltipArrowProps>(
|
|
|
599
599
|
|
|
600
600
|
TooltipArrow.displayName = ARROW_NAME;
|
|
601
601
|
|
|
602
|
-
/* ----------------------------------------------------------------------------------------------- */
|
|
603
|
-
|
|
604
602
|
type TooltipSide = NonNullable<TooltipContentProps['side']>;
|
|
605
603
|
|
|
606
604
|
const getExitSideFromRect = (point: Point, rect: DOMRect): TooltipSide => {
|
|
@@ -755,6 +753,10 @@ const getHullPresorted = <P extends Point>(points: Readonly<Array<P>>): Array<P>
|
|
|
755
753
|
}
|
|
756
754
|
};
|
|
757
755
|
|
|
756
|
+
//
|
|
757
|
+
// Tooltip
|
|
758
|
+
//
|
|
759
|
+
|
|
758
760
|
export const Tooltip = {
|
|
759
761
|
Provider: TooltipProvider,
|
|
760
762
|
Trigger: TooltipTrigger,
|
package/src/components/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { type Resource, type TFunction } from 'i18next';
|
|
|
6
6
|
export { Trans } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
export * from '@dxos/react-hooks';
|
|
9
|
-
export * from '@dxos/
|
|
9
|
+
export * from '@dxos/ui-types';
|
|
10
10
|
|
|
11
11
|
export * from './components';
|
|
12
12
|
export * from './hooks';
|