@noya-app/noya-designsystem 0.1.77 → 0.1.79
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/.turbo/turbo-build.log +20 -12
- package/CHANGELOG.md +15 -0
- package/dist/chunk-D57E6H3M.mjs +36 -0
- package/dist/chunk-D57E6H3M.mjs.map +1 -0
- package/dist/chunk-FJ6ZGZIA.mjs +43 -0
- package/dist/chunk-FJ6ZGZIA.mjs.map +1 -0
- package/dist/emojis.d.mts +1 -0
- package/dist/emojis.d.ts +1 -0
- package/dist/emojis.js +31 -0
- package/dist/emojis.js.map +1 -0
- package/dist/emojis.mjs +8 -0
- package/dist/emojis.mjs.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +142 -90
- package/dist/index.d.ts +142 -90
- package/dist/index.js +30559 -6412
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35081 -10928
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -17
- package/src/__tests__/__snapshots__/fuzzyScorer.test.ts.snap +1 -1
- package/src/components/Avatar.tsx +10 -10
- package/src/components/Banner.tsx +1 -1
- package/src/components/BaseToolbar.tsx +1 -1
- package/src/components/Button.tsx +2 -1
- package/src/components/Chip.tsx +1 -1
- package/src/components/ColorSwatchControl.tsx +22 -14
- package/src/components/CommandPalette.tsx +10 -6
- package/src/components/ContextMenu.tsx +249 -38
- package/src/components/Dialog.tsx +70 -67
- package/src/components/Drawer.tsx +56 -17
- package/src/components/DropdownMenu.tsx +305 -46
- package/src/components/EditableText.tsx +1 -1
- package/src/components/EmojiPicker.tsx +645 -0
- package/src/components/GridView.tsx +5 -1
- package/src/components/IVirtualizedList.tsx +21 -1
- package/src/components/InputField.tsx +2 -10
- package/src/components/InspectorContainer.tsx +4 -2
- package/src/components/Message.tsx +5 -16
- package/src/components/Popover.tsx +73 -107
- package/src/components/Progress.tsx +18 -18
- package/src/components/ScrollArea.tsx +66 -31
- package/src/components/ScrollableSidebar.tsx +1 -1
- package/src/components/SegmentedControl.tsx +166 -38
- package/src/components/SelectMenu.tsx +193 -101
- package/src/components/Slider.tsx +40 -38
- package/src/components/Switch.tsx +4 -4
- package/src/components/TextArea.tsx +1 -1
- package/src/components/Toast.tsx +99 -26
- package/src/components/Toolbar.tsx +114 -16
- package/src/components/Tooltip.tsx +18 -8
- package/src/components/Virtualized.tsx +193 -14
- package/src/components/VisuallyHidden.tsx +20 -0
- package/src/components/__tests__/Virtualized.math.test.ts +426 -1
- package/src/components/__tests__/Virtualized.test.tsx +129 -1
- package/src/components/ai-assistant/AIAssistantLayout.tsx +11 -6
- package/src/components/internal/Menu.tsx +4 -0
- package/src/components/listView/ListViewEditableRowTitle.tsx +1 -1
- package/src/components/listView/ListViewRoot.tsx +5 -1
- package/src/components/resizablePanels/Panel.tsx +94 -0
- package/src/components/resizablePanels/PanelGroup.tsx +498 -0
- package/src/components/resizablePanels/PanelGroupContext.tsx +14 -0
- package/src/components/resizablePanels/PanelResizeHandle.tsx +61 -0
- package/src/components/resizablePanels/index.ts +7 -0
- package/src/components/resizablePanels/types.ts +65 -0
- package/src/components/workspace/DrawerWorkspaceLayout.tsx +22 -7
- package/src/components/workspace/PanelWorkspaceLayout.tsx +30 -84
- package/src/components/workspace/WorkspaceLayout.tsx +28 -58
- package/src/components/workspace/types.ts +6 -4
- package/src/contexts/DialogContext.tsx +15 -24
- package/src/emojis.ts +1 -0
- package/src/hooks/useTriggerToggle.ts +95 -0
- package/src/index.css +2 -0
- package/src/index.tsx +1 -2
- package/src/theme/proseTheme.ts +2 -0
- package/src/utils/mergeProps.ts +57 -0
- package/src/utils/skinTone.ts +90 -0
- package/tsup.config.ts +3 -1
- package/src/__tests__/workspaceLayout.test.ts +0 -281
- package/src/components/ScrollArea2.tsx +0 -76
- package/src/components/internal/MenuViewport.tsx +0 -178
- package/src/components/internal/SelectItem.tsx +0 -138
- package/src/components/workspace/panelStorage.ts +0 -216
|
@@ -42,7 +42,7 @@ export const InspectorContainer = memo(
|
|
|
42
42
|
>
|
|
43
43
|
{header}
|
|
44
44
|
{children ? (
|
|
45
|
-
<ScrollArea>
|
|
45
|
+
<ScrollArea className="n-flex-1 n-min-h-0">
|
|
46
46
|
<div className="n-flex n-flex-col n-relative">
|
|
47
47
|
{showDividers
|
|
48
48
|
? withSeparatorElements(children, <Divider />)
|
|
@@ -50,7 +50,9 @@ export const InspectorContainer = memo(
|
|
|
50
50
|
</div>
|
|
51
51
|
</ScrollArea>
|
|
52
52
|
) : fallback ? (
|
|
53
|
-
<div className="n-flex n-flex-col n-relative n-h-full">
|
|
53
|
+
<div className="n-flex n-flex-col n-relative n-h-full">
|
|
54
|
+
{fallback}
|
|
55
|
+
</div>
|
|
54
56
|
) : null}
|
|
55
57
|
</div>
|
|
56
58
|
);
|
|
@@ -5,7 +5,6 @@ import { uuid } from "@noya-app/noya-utils";
|
|
|
5
5
|
import React, { forwardRef, memo, useMemo } from "react";
|
|
6
6
|
import { cssVars, INPUT_HEIGHT } from "../theme";
|
|
7
7
|
import { cx } from "../utils/classNames";
|
|
8
|
-
import { colorFromString } from "../utils/colorFromString";
|
|
9
8
|
import { Avatar } from "./Avatar";
|
|
10
9
|
import { Logo } from "./NoyaLogo";
|
|
11
10
|
|
|
@@ -22,18 +21,8 @@ export const Message = memo(
|
|
|
22
21
|
{ role, children, user, avatarSize = INPUT_HEIGHT }: MessageProps,
|
|
23
22
|
ref: React.ForwardedRef<HTMLDivElement>
|
|
24
23
|
) {
|
|
25
|
-
const randomId = uuid();
|
|
24
|
+
const randomId = useMemo(() => uuid(), []);
|
|
26
25
|
const resolvedUserId = user?.authId ?? user?.connectionId ?? randomId;
|
|
27
|
-
const userMessageBackgroundColor = colorFromString(resolvedUserId);
|
|
28
|
-
const styles = useMemo(
|
|
29
|
-
() =>
|
|
30
|
-
role === "user"
|
|
31
|
-
? {
|
|
32
|
-
backgroundColor: userMessageBackgroundColor,
|
|
33
|
-
}
|
|
34
|
-
: undefined,
|
|
35
|
-
[userMessageBackgroundColor, role]
|
|
36
|
-
);
|
|
37
26
|
return (
|
|
38
27
|
<div
|
|
39
28
|
className={cx(
|
|
@@ -60,11 +49,11 @@ export const Message = memo(
|
|
|
60
49
|
<div
|
|
61
50
|
className={cx(
|
|
62
51
|
"markdown-message",
|
|
63
|
-
"n-
|
|
64
|
-
role === "user"
|
|
65
|
-
|
|
52
|
+
"n-rounded-lg n-py-2 n-px-3 n-transition-all n-duration-200 n-max-w-[70%] n-min-w-0 n-text-sm [&_pre]:n-whitespace-pre-wrap [&_code]:n-whitespace-pre-wrap",
|
|
53
|
+
role === "user"
|
|
54
|
+
? "n-text-white n-ml-auto n-bg-primary"
|
|
55
|
+
: "n-text-text n-bg-input-background"
|
|
66
56
|
)}
|
|
67
|
-
style={styles}
|
|
68
57
|
ref={ref}
|
|
69
58
|
>
|
|
70
59
|
{children}
|
|
@@ -1,39 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
|
3
4
|
import { useControlledOrUncontrolled } from "@noya-app/react-utils";
|
|
4
|
-
import {
|
|
5
|
-
import React, {
|
|
6
|
-
ComponentProps,
|
|
7
|
-
useCallback,
|
|
8
|
-
useEffect,
|
|
9
|
-
useId,
|
|
10
|
-
useRef,
|
|
11
|
-
} from "react";
|
|
5
|
+
import React, { useCallback, useEffect, useId } from "react";
|
|
12
6
|
import { useOpenPortalsControls } from "../contexts/OpenPortalsContext";
|
|
13
7
|
import {
|
|
14
8
|
portalScopeProps,
|
|
15
9
|
usePortalScopeId,
|
|
16
10
|
} from "../contexts/PortalScopeContext";
|
|
11
|
+
import { useTriggerToggle } from "../hooks/useTriggerToggle";
|
|
17
12
|
import { cx } from "../utils/classNames";
|
|
13
|
+
import { mergePropsWithEventComposition } from "../utils/mergeProps";
|
|
18
14
|
import { IconButton } from "./IconButton";
|
|
19
15
|
|
|
20
|
-
const closeStyles: React.CSSProperties = {
|
|
21
|
-
all: "unset",
|
|
22
|
-
fontFamily: "inherit",
|
|
23
|
-
};
|
|
24
|
-
|
|
25
16
|
type PopoverVariant = "normal" | "large";
|
|
26
17
|
|
|
27
|
-
interface Props
|
|
28
|
-
extends Pick<
|
|
29
|
-
ComponentProps<(typeof PopoverPrimitive)["Content"]>,
|
|
30
|
-
| "onOpenAutoFocus"
|
|
31
|
-
| "onCloseAutoFocus"
|
|
32
|
-
| "onPointerDownOutside"
|
|
33
|
-
| "onInteractOutside"
|
|
34
|
-
| "onFocusOutside"
|
|
35
|
-
| "side"
|
|
36
|
-
> {
|
|
18
|
+
interface Props {
|
|
37
19
|
children:
|
|
38
20
|
| React.ReactNode
|
|
39
21
|
| ((props: { close: () => void }) => React.ReactNode);
|
|
@@ -48,11 +30,16 @@ interface Props
|
|
|
48
30
|
className?: string;
|
|
49
31
|
style?: React.CSSProperties;
|
|
50
32
|
portalContainer?: HTMLElement | null;
|
|
33
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
34
|
+
/**
|
|
35
|
+
* Called when an interaction outside the popover occurs.
|
|
36
|
+
* Return false to prevent the popover from closing.
|
|
37
|
+
*/
|
|
38
|
+
shouldCloseOnInteractOutside?: (event: PointerEvent) => boolean;
|
|
51
39
|
}
|
|
52
40
|
|
|
53
41
|
export const popoverStyle = {
|
|
54
|
-
base:
|
|
55
|
-
"n-rounded n-font-[14px] n-bg-popover-background n-shadow-popover n-max-h-[600px] n-overflow-y-auto n-text-text-muted n-z-[1000]",
|
|
42
|
+
base: "n-rounded n-font-[14px] n-bg-popover-background n-shadow-popover n-max-h-[600px] n-overflow-y-auto n-text-text-muted n-z-[1000]",
|
|
56
43
|
large: "n-w-[680px]",
|
|
57
44
|
normal: "n-w-[240px]",
|
|
58
45
|
};
|
|
@@ -67,19 +54,14 @@ export function Popover({
|
|
|
67
54
|
sideOffset = 4,
|
|
68
55
|
showArrow = true,
|
|
69
56
|
onOpenChange,
|
|
70
|
-
onOpenAutoFocus,
|
|
71
|
-
onCloseAutoFocus,
|
|
72
|
-
onPointerDownOutside,
|
|
73
|
-
onInteractOutside,
|
|
74
|
-
onFocusOutside,
|
|
75
57
|
onClickClose,
|
|
76
58
|
className,
|
|
77
59
|
portalContainer,
|
|
78
60
|
style,
|
|
61
|
+
shouldCloseOnInteractOutside,
|
|
79
62
|
}: Props) {
|
|
80
63
|
const defaultId = useId();
|
|
81
64
|
const portalScopeId = usePortalScopeId();
|
|
82
|
-
const contentRef = useRef<HTMLDivElement>(null);
|
|
83
65
|
const [isOpen, setIsOpen] = useControlledOrUncontrolled({
|
|
84
66
|
value: open,
|
|
85
67
|
onChange: onOpenChange,
|
|
@@ -87,6 +69,9 @@ export function Popover({
|
|
|
87
69
|
});
|
|
88
70
|
const close = useCallback(() => setIsOpen(false), [setIsOpen]);
|
|
89
71
|
|
|
72
|
+
const { anchorElement, setAnchorElement, popupRef, handleOpenChange } =
|
|
73
|
+
useTriggerToggle(isOpen, setIsOpen, { shouldCloseOnInteractOutside });
|
|
74
|
+
|
|
90
75
|
const { addOpenPortal, removeOpenPortal } = useOpenPortalsControls();
|
|
91
76
|
|
|
92
77
|
useEffect(() => {
|
|
@@ -100,91 +85,72 @@ export function Popover({
|
|
|
100
85
|
}, [addOpenPortal, isOpen, portalScopeId, removeOpenPortal, defaultId]);
|
|
101
86
|
|
|
102
87
|
return (
|
|
103
|
-
<PopoverPrimitive.Root open={isOpen} onOpenChange={
|
|
104
|
-
<PopoverPrimitive.Trigger
|
|
88
|
+
<PopoverPrimitive.Root open={isOpen} onOpenChange={handleOpenChange}>
|
|
89
|
+
<PopoverPrimitive.Trigger
|
|
90
|
+
render={(triggerProps) => {
|
|
91
|
+
const element = React.isValidElement(trigger) ? (
|
|
92
|
+
trigger
|
|
93
|
+
) : (
|
|
94
|
+
<span>{trigger}</span>
|
|
95
|
+
);
|
|
96
|
+
const childProps = element.props as Record<string, unknown>;
|
|
97
|
+
const mergedProps = mergePropsWithEventComposition(
|
|
98
|
+
triggerProps as Record<string, unknown>,
|
|
99
|
+
childProps
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Custom ref handling for anchor tracking
|
|
103
|
+
mergedProps.ref = (node: Element | null) => {
|
|
104
|
+
// Only update state when we get a valid node to prevent anchor loss during rerenders
|
|
105
|
+
if (node) setAnchorElement(node);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return React.cloneElement(
|
|
109
|
+
element as React.ReactElement<any>,
|
|
110
|
+
mergedProps
|
|
111
|
+
);
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
105
114
|
<PopoverPrimitive.Portal container={portalContainer}>
|
|
106
|
-
<PopoverPrimitive.
|
|
115
|
+
<PopoverPrimitive.Positioner
|
|
107
116
|
{...portalScopeProps(portalScopeId)}
|
|
108
|
-
|
|
109
|
-
style={style}
|
|
110
|
-
className={cx(
|
|
111
|
-
popoverStyle.base,
|
|
112
|
-
variant === "large" && popoverStyle.large,
|
|
113
|
-
variant === "normal" && popoverStyle.normal,
|
|
114
|
-
className
|
|
115
|
-
)}
|
|
117
|
+
anchor={anchorElement}
|
|
116
118
|
side={side}
|
|
117
119
|
align="center"
|
|
118
120
|
sideOffset={sideOffset}
|
|
119
|
-
onOpenAutoFocus={onOpenAutoFocus}
|
|
120
|
-
onCloseAutoFocus={onCloseAutoFocus}
|
|
121
|
-
onInteractOutside={onInteractOutside}
|
|
122
|
-
onFocusOutside={onFocusOutside}
|
|
123
|
-
onPointerDownOutside={(event) => {
|
|
124
|
-
if (
|
|
125
|
-
isEventInsideElement(
|
|
126
|
-
event.detail.originalEvent,
|
|
127
|
-
contentRef.current
|
|
128
|
-
)
|
|
129
|
-
) {
|
|
130
|
-
event.preventDefault();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
onPointerDownOutside?.(event);
|
|
134
|
-
}}
|
|
135
121
|
collisionPadding={8}
|
|
136
122
|
arrowPadding={2}
|
|
137
|
-
|
|
138
|
-
// onPointerDown={(event) => {
|
|
139
|
-
// event.stopPropagation();
|
|
140
|
-
// }}
|
|
141
|
-
// onWheel={(event) => {
|
|
142
|
-
// event.stopPropagation();
|
|
143
|
-
// }}
|
|
123
|
+
className="n-z-menu"
|
|
144
124
|
>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
125
|
+
<PopoverPrimitive.Popup
|
|
126
|
+
ref={popupRef}
|
|
127
|
+
style={style}
|
|
128
|
+
className={cx(
|
|
129
|
+
popoverStyle.base,
|
|
130
|
+
variant === "large" && popoverStyle.large,
|
|
131
|
+
variant === "normal" && popoverStyle.normal,
|
|
132
|
+
className
|
|
133
|
+
)}
|
|
134
|
+
>
|
|
135
|
+
{typeof children === "function" ? children({ close }) : children}
|
|
136
|
+
{showArrow && (
|
|
137
|
+
<PopoverPrimitive.Arrow className="n-fill-popover-background" />
|
|
138
|
+
)}
|
|
139
|
+
{closable && (
|
|
140
|
+
<PopoverPrimitive.Close
|
|
141
|
+
className="n-rounded-full n-h-[25px] n-w-[25px] n-inline-flex n-items-center n-justify-center n-absolute n-top-[5px] n-right-[5px]"
|
|
142
|
+
render={
|
|
143
|
+
<IconButton
|
|
144
|
+
iconName="Cross2Icon"
|
|
145
|
+
onClick={onClickClose}
|
|
146
|
+
style={{ all: "unset", fontFamily: "inherit" }}
|
|
147
|
+
/>
|
|
148
|
+
}
|
|
149
|
+
/>
|
|
150
|
+
)}
|
|
151
|
+
</PopoverPrimitive.Popup>
|
|
152
|
+
</PopoverPrimitive.Positioner>
|
|
158
153
|
</PopoverPrimitive.Portal>
|
|
159
154
|
</PopoverPrimitive.Root>
|
|
160
155
|
);
|
|
161
156
|
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Radix ignores pointer-events on the body when a popover is open.
|
|
165
|
-
* This function checks if an event is inside an element by temporarily
|
|
166
|
-
* setting pointer-events to auto and then restoring it afterward.
|
|
167
|
-
*/
|
|
168
|
-
function isEventInsideElement(
|
|
169
|
-
event: PointerEvent,
|
|
170
|
-
element: HTMLElement | null
|
|
171
|
-
) {
|
|
172
|
-
if (!element) return false;
|
|
173
|
-
|
|
174
|
-
const body = document.body;
|
|
175
|
-
const originalPointerEvents = body.style.pointerEvents;
|
|
176
|
-
body.style.pointerEvents = "auto";
|
|
177
|
-
|
|
178
|
-
// Get all elements at the point
|
|
179
|
-
const elementsAtPoint = document.elementsFromPoint(
|
|
180
|
-
event.clientX,
|
|
181
|
-
event.clientY
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
// Restore original pointer-events
|
|
185
|
-
body.style.pointerEvents = originalPointerEvents;
|
|
186
|
-
|
|
187
|
-
const target = elementsAtPoint.at(0);
|
|
188
|
-
|
|
189
|
-
return target && element.contains(target);
|
|
190
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { clamp } from "@noya-app/noya-utils";
|
|
4
|
-
import { Progress as ProgressPrimitive } from "
|
|
4
|
+
import { Progress as ProgressPrimitive } from "@base-ui/react/progress";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import { cx } from "../utils/classNames";
|
|
7
7
|
|
|
@@ -23,19 +23,17 @@ export function Progress({
|
|
|
23
23
|
style?: React.CSSProperties;
|
|
24
24
|
}) {
|
|
25
25
|
const clampedValue = clamp(value, 0, 100);
|
|
26
|
-
const transformStyles = React.useMemo(
|
|
27
|
-
() => ({
|
|
28
|
-
transform: `translateX(-${100 - clampedValue}%)`,
|
|
29
|
-
backgroundColor: color,
|
|
30
|
-
}),
|
|
31
|
-
[color, clampedValue]
|
|
32
|
-
);
|
|
33
26
|
|
|
34
27
|
const style = React.useMemo(
|
|
35
28
|
() => ({ transform: "translateZ(0)", ...styleProp }),
|
|
36
29
|
[styleProp]
|
|
37
30
|
);
|
|
38
31
|
|
|
32
|
+
const indicatorStyle = React.useMemo(
|
|
33
|
+
() => ({ backgroundColor: color }),
|
|
34
|
+
[color]
|
|
35
|
+
);
|
|
36
|
+
|
|
39
37
|
return (
|
|
40
38
|
<ProgressPrimitive.Root
|
|
41
39
|
className={cx(
|
|
@@ -45,16 +43,18 @@ export function Progress({
|
|
|
45
43
|
style={style}
|
|
46
44
|
value={clampedValue}
|
|
47
45
|
>
|
|
48
|
-
<ProgressPrimitive.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
46
|
+
<ProgressPrimitive.Track className="n-w-full n-h-full">
|
|
47
|
+
<ProgressPrimitive.Indicator
|
|
48
|
+
className={cx(
|
|
49
|
+
"n-transition-[width_660ms_cubic-bezier(0.65,0,0.35,1)] n-h-full",
|
|
50
|
+
colorScheme === "primary" && "n-bg-primary",
|
|
51
|
+
colorScheme === "secondary" && "n-bg-secondary",
|
|
52
|
+
colorScheme === "warning" && "n-bg-warning",
|
|
53
|
+
colorScheme === "normal" && "n-bg-text"
|
|
54
|
+
)}
|
|
55
|
+
style={indicatorStyle}
|
|
56
|
+
/>
|
|
57
|
+
</ProgressPrimitive.Track>
|
|
58
58
|
</ProgressPrimitive.Root>
|
|
59
59
|
);
|
|
60
60
|
}
|
|
@@ -1,41 +1,76 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { ScrollArea as
|
|
3
|
+
import { ScrollArea as BScrollArea } from "@base-ui/react/scroll-area";
|
|
4
4
|
import * as React from "react";
|
|
5
|
+
import { cx } from "../utils/classNames";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const SCROLLBAR_STATE_CLASSES =
|
|
8
|
+
"scroll-component n-opacity-0 n-transition-opacity n-delay-300 n-pointer-events-none data-[hovering]:n-opacity-100 data-[hovering]:n-delay-0 data-[hovering]:n-duration-75 data-[hovering]:n-pointer-events-auto data-[scrolling]:n-opacity-100 data-[scrolling]:n-delay-0 data-[scrolling]:n-duration-75 data-[scrolling]:n-pointer-events-auto";
|
|
9
|
+
|
|
10
|
+
const SCROLLBAR_TRACK_VERTICAL =
|
|
11
|
+
"n-m-1 n-w-1 flex n-justify-center n-rounded-md n-bg-divider-subtle";
|
|
12
|
+
const SCROLLBAR_TRACK_HORIZONTAL =
|
|
13
|
+
"n-m-1 n-h-1 flex n-justify-center n-rounded-md n-bg-divider-subtle";
|
|
14
|
+
|
|
15
|
+
const SCROLLBAR_THUMB_VERTICAL =
|
|
16
|
+
"scroll-component n-w-full n-rounded n-bg-scrollbar";
|
|
17
|
+
const SCROLLBAR_THUMB_HORIZONTAL =
|
|
18
|
+
"scroll-component n-h-full n-rounded n-bg-scrollbar";
|
|
11
19
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
type ScrollAreaViewportProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
21
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function ScrollArea({
|
|
25
|
+
children,
|
|
26
|
+
className,
|
|
27
|
+
viewportClassName,
|
|
28
|
+
orientation = "vertical",
|
|
29
|
+
style,
|
|
30
|
+
viewportProps,
|
|
31
|
+
}: {
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
className?: string;
|
|
34
|
+
viewportClassName?: string;
|
|
35
|
+
orientation?: "vertical" | "horizontal" | "both";
|
|
36
|
+
style?: React.CSSProperties;
|
|
37
|
+
viewportProps?: ScrollAreaViewportProps;
|
|
38
|
+
}) {
|
|
39
|
+
const {
|
|
40
|
+
className: viewportPropsClassName,
|
|
41
|
+
ref: viewportRef,
|
|
42
|
+
...viewportRest
|
|
43
|
+
} = viewportProps ?? {};
|
|
15
44
|
|
|
16
45
|
return (
|
|
17
|
-
<
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
46
|
+
<BScrollArea.Root className={cx("n-relative", className)} style={style}>
|
|
47
|
+
<BScrollArea.Viewport
|
|
48
|
+
ref={viewportRef}
|
|
49
|
+
className={cx(
|
|
50
|
+
"n-h-full n-overscroll-contain",
|
|
51
|
+
viewportClassName,
|
|
52
|
+
viewportPropsClassName
|
|
53
|
+
)}
|
|
54
|
+
{...viewportRest}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</BScrollArea.Viewport>
|
|
58
|
+
{(orientation === "vertical" || orientation === "both") && (
|
|
59
|
+
<BScrollArea.Scrollbar
|
|
60
|
+
className={cx(SCROLLBAR_STATE_CLASSES, SCROLLBAR_TRACK_VERTICAL)}
|
|
25
61
|
>
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
orientation="vertical"
|
|
34
|
-
className="n-scroll-component n-flex n-p-[3px] data-[orientation=vertical]:n-w-[10px]"
|
|
62
|
+
<BScrollArea.Thumb className={SCROLLBAR_THUMB_VERTICAL} />
|
|
63
|
+
</BScrollArea.Scrollbar>
|
|
64
|
+
)}
|
|
65
|
+
{(orientation === "horizontal" || orientation === "both") && (
|
|
66
|
+
<BScrollArea.Scrollbar
|
|
67
|
+
orientation="horizontal"
|
|
68
|
+
className={cx(SCROLLBAR_STATE_CLASSES, SCROLLBAR_TRACK_HORIZONTAL)}
|
|
35
69
|
>
|
|
36
|
-
<
|
|
37
|
-
</
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
<BScrollArea.Thumb className={SCROLLBAR_THUMB_HORIZONTAL} />
|
|
71
|
+
</BScrollArea.Scrollbar>
|
|
72
|
+
)}
|
|
73
|
+
{orientation === "both" && <BScrollArea.Corner />}
|
|
74
|
+
</BScrollArea.Root>
|
|
40
75
|
);
|
|
41
|
-
}
|
|
76
|
+
}
|
|
@@ -4,7 +4,7 @@ import { ScrollArea } from "./ScrollArea";
|
|
|
4
4
|
export function ScrollableSidebar({ children }: { children: React.ReactNode }) {
|
|
5
5
|
return (
|
|
6
6
|
<div className="n-relative n-flex n-flex-col n-flex-1 n-max-h-full">
|
|
7
|
-
<ScrollArea>{children}</ScrollArea>
|
|
7
|
+
<ScrollArea className="n-flex-1 n-min-h-0">{children}</ScrollArea>
|
|
8
8
|
</div>
|
|
9
9
|
);
|
|
10
10
|
}
|