@noya-app/noya-designsystem 0.1.30 → 0.1.32
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/.turbo/turbo-lint.log +15 -1
- package/CHANGELOG.md +17 -0
- package/README.md +13 -1
- package/dist/index.css +1 -0
- package/dist/index.d.ts +238 -627
- package/dist/index.js +4259 -2862
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4159 -2764
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -7
- package/src/components/ActivityIndicator.tsx +4 -36
- package/src/components/Avatar.tsx +63 -62
- package/src/components/Button.tsx +53 -170
- package/src/components/Chip.tsx +117 -150
- package/src/components/ContextMenu.tsx +13 -35
- package/src/components/Dialog.tsx +66 -54
- package/src/components/Divider.tsx +31 -41
- package/src/components/DraggableMenuButton.tsx +29 -30
- package/src/components/DropdownMenu.tsx +30 -40
- package/src/components/FillInputField.tsx +16 -26
- package/src/components/FillPreviewBackground.tsx +18 -22
- package/src/components/FloatingWindow.tsx +4 -7
- package/src/components/GridView.tsx +70 -200
- package/src/components/IconButton.tsx +1 -5
- package/src/components/InputField.tsx +258 -234
- package/src/components/InputFieldWithCompletions.tsx +20 -27
- package/src/components/InspectorContainer.tsx +4 -9
- package/src/components/InspectorPrimitives.tsx +135 -109
- package/src/components/Label.tsx +5 -36
- package/src/components/LabeledElementView.tsx +5 -26
- package/src/components/ListView.tsx +239 -167
- package/src/components/Popover.tsx +15 -39
- package/src/components/Progress.tsx +21 -44
- package/src/components/RadioGroup.tsx +6 -71
- package/src/components/ScrollArea.tsx +11 -39
- package/src/components/SelectMenu.tsx +72 -32
- package/src/components/Slider.tsx +7 -43
- package/src/components/Spacer.tsx +6 -18
- package/src/components/Switch.tsx +4 -42
- package/src/components/Text.tsx +31 -66
- package/src/components/TextArea.tsx +5 -31
- package/src/components/Toast.tsx +15 -57
- package/src/components/Tooltip.tsx +4 -13
- package/src/components/WorkspaceLayout.tsx +27 -17
- package/src/components/internal/Menu.tsx +37 -83
- package/src/contexts/DesignSystemConfiguration.tsx +1 -47
- package/src/contexts/DialogContext.tsx +2 -10
- package/src/hooks/useDarkMode.ts +14 -0
- package/src/index.css +108 -0
- package/src/index.tsx +4 -5
- package/src/theme/index.ts +4 -16
- package/src/utils/tailwind.ts +17 -0
- package/tailwind.config.ts +223 -0
- package/tailwind.d.ts +11 -0
- package/tsconfig.json +4 -1
- package/tsup.config.ts +16 -0
- package/dist/index.d.mts +0 -1455
- package/src/components/Grid.tsx +0 -54
- package/src/components/Select.tsx +0 -183
- package/src/components/Stack.tsx +0 -155
- package/src/theme/dark.ts +0 -45
- package/src/theme/light.ts +0 -226
- package/src/utils/breakpoints.ts +0 -45
package/src/components/Text.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { ForwardedRef, forwardRef, ReactHTML, ReactNode } from "react";
|
|
2
|
-
import
|
|
3
|
-
import { Theme, ThemeColorName } from "../theme";
|
|
4
|
-
import { BreakpointCollection, mergeBreakpoints } from "../utils/breakpoints";
|
|
2
|
+
import { camelCaseToKebabCase, ThemeColor } from "../utils/tailwind";
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
type Variant = "title" | "subtitle" | "heading1" | "heading2" | "heading3" | "heading4" | "heading5" | "body" | "small" | "button" | "code" | "label";
|
|
5
|
+
|
|
6
|
+
const elements: Record<Variant, keyof ReactHTML> = {
|
|
7
7
|
title: "h1",
|
|
8
8
|
subtitle: "h1",
|
|
9
9
|
heading1: "h1",
|
|
@@ -18,47 +18,28 @@ const elements: Record<keyof Theme["textStyles"], keyof ReactHTML> = {
|
|
|
18
18
|
label: "span",
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
maxWidth?: CSSProperties["maxWidth"];
|
|
38
|
-
opacity?: CSSProperties["opacity"];
|
|
39
|
-
position?: CSSProperties["position"];
|
|
40
|
-
overflow?: CSSProperties["overflow"];
|
|
41
|
-
textOverflow?: CSSProperties["textOverflow"];
|
|
42
|
-
textDecoration?: CSSProperties["textDecoration"];
|
|
43
|
-
display?: CSSProperties["display"];
|
|
44
|
-
top?: CSSProperties["top"];
|
|
45
|
-
right?: CSSProperties["right"];
|
|
46
|
-
bottom?: CSSProperties["bottom"];
|
|
47
|
-
left?: CSSProperties["left"];
|
|
48
|
-
userSelect?: CSSProperties["userSelect"];
|
|
49
|
-
cursor?: CSSProperties["cursor"];
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type TextBreakpointList = BreakpointCollection<StyleProps>;
|
|
53
|
-
|
|
54
|
-
interface Props extends StyleProps {
|
|
21
|
+
export const textStyles: Record<Variant, string> = {
|
|
22
|
+
title: "font-sans text-title font-bold sm:text-[36px]",
|
|
23
|
+
subtitle: "font-sans text-subtitle font-medium sm:text-[18px]",
|
|
24
|
+
heading1: "font-sans text-heading1 font-semibold",
|
|
25
|
+
heading2: "font-sans text-heading2 font-medium",
|
|
26
|
+
heading3: "font-sans text-heading3 font-normal",
|
|
27
|
+
heading4: "font-sans text-heading4 font-medium",
|
|
28
|
+
heading5: "font-sans text-heading5 font-medium",
|
|
29
|
+
body: "font-sans text-base font-normal",
|
|
30
|
+
small: "font-sans text-heading5 font-normal",
|
|
31
|
+
button: "font-sans text-button font-medium",
|
|
32
|
+
code: "font-mono text-code",
|
|
33
|
+
label: "font-sans text-label font-normal uppercase",
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
export type TextProps = {
|
|
55
37
|
as?: keyof ReactHTML;
|
|
56
38
|
href?: string;
|
|
57
39
|
className?: string;
|
|
58
40
|
style?: React.CSSProperties;
|
|
59
|
-
variant:
|
|
60
|
-
|
|
61
|
-
color?: ThemeColorName;
|
|
41
|
+
variant: Variant;
|
|
42
|
+
color?: ThemeColor;
|
|
62
43
|
children: ReactNode;
|
|
63
44
|
onClick?: () => void;
|
|
64
45
|
onDoubleClick?: () => void;
|
|
@@ -66,58 +47,42 @@ interface Props extends StyleProps {
|
|
|
66
47
|
tabIndex?: number;
|
|
67
48
|
}
|
|
68
49
|
|
|
69
|
-
const StyledElement = styled.span<{
|
|
70
|
-
$variant: keyof Theme["textStyles"];
|
|
71
|
-
$styleProps: StyleProps;
|
|
72
|
-
$color: ThemeColorName;
|
|
73
|
-
$breakpoints: BreakpointCollection<StyleProps> | null | false;
|
|
74
|
-
}>(({ theme, $variant, $styleProps, $breakpoints, $color }) => ({
|
|
75
|
-
...(theme.textStyles as any)[$variant],
|
|
76
|
-
color: $color ? theme.colors[$color] : undefined,
|
|
77
|
-
...$styleProps,
|
|
78
|
-
...mergeBreakpoints($breakpoints || []),
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
50
|
export const Text = forwardRef(function Text(
|
|
82
51
|
{
|
|
83
52
|
as,
|
|
84
53
|
variant,
|
|
85
|
-
breakpoints,
|
|
86
54
|
children,
|
|
87
55
|
className,
|
|
88
|
-
color,
|
|
56
|
+
color = "text",
|
|
89
57
|
href,
|
|
90
58
|
tabIndex,
|
|
91
59
|
onClick,
|
|
92
60
|
onKeyDown,
|
|
93
61
|
style,
|
|
94
62
|
...rest
|
|
95
|
-
}:
|
|
63
|
+
}: TextProps,
|
|
96
64
|
forwardedRef: ForwardedRef<HTMLElement>
|
|
97
65
|
) {
|
|
98
|
-
const
|
|
66
|
+
const Component = as ?? elements[variant] ?? "span";
|
|
99
67
|
|
|
100
68
|
return (
|
|
101
|
-
<
|
|
69
|
+
<Component
|
|
70
|
+
// @ts-expect-error expected to be many semantic html elements
|
|
102
71
|
ref={forwardedRef}
|
|
103
|
-
|
|
104
|
-
className={className}
|
|
72
|
+
className={`${textStyles[variant]} text-${camelCaseToKebabCase(String(color)) ?? "text"} ${className ?? ""}`}
|
|
105
73
|
style={style}
|
|
106
74
|
tabIndex={tabIndex}
|
|
107
|
-
$variant={variant}
|
|
108
|
-
$breakpoints={breakpoints}
|
|
109
|
-
$styleProps={rest}
|
|
110
|
-
$color={color}
|
|
111
75
|
onClick={onClick}
|
|
112
76
|
onKeyDown={onKeyDown}
|
|
113
77
|
{...((href && { href }) as any)}
|
|
78
|
+
{...rest}
|
|
114
79
|
>
|
|
115
80
|
{children}
|
|
116
|
-
</
|
|
81
|
+
</Component>
|
|
117
82
|
);
|
|
118
83
|
});
|
|
119
84
|
|
|
120
|
-
type PresetProps = Omit<
|
|
85
|
+
type PresetProps = Omit<TextProps, "variant">;
|
|
121
86
|
|
|
122
87
|
export const Heading1 = forwardRef(
|
|
123
88
|
(props: PresetProps, ref: ForwardedRef<HTMLElement>) => (
|
|
@@ -1,30 +1,5 @@
|
|
|
1
1
|
import { assignRef } from "@noya-app/react-utils";
|
|
2
2
|
import React, { forwardRef, memo, useCallback, useEffect, useRef } from "react";
|
|
3
|
-
import styled from "styled-components";
|
|
4
|
-
|
|
5
|
-
const TextAreaElement = styled.textarea(({ theme }) => ({
|
|
6
|
-
...theme.textStyles.small,
|
|
7
|
-
color: theme.colors.text,
|
|
8
|
-
background: theme.colors.inputBackground,
|
|
9
|
-
width: "0px",
|
|
10
|
-
flex: "1 1 auto",
|
|
11
|
-
padding: "4px 6px",
|
|
12
|
-
border: "none",
|
|
13
|
-
outline: "none",
|
|
14
|
-
height: 100,
|
|
15
|
-
borderRadius: "4px",
|
|
16
|
-
"&::placeholder": {
|
|
17
|
-
color: theme.colors.textDisabled,
|
|
18
|
-
},
|
|
19
|
-
"&:focus": {
|
|
20
|
-
boxShadow: `0 0 0 2px ${theme.colors.primary}`,
|
|
21
|
-
},
|
|
22
|
-
// readonly
|
|
23
|
-
"&:read-only": {
|
|
24
|
-
color: theme.colors.textDisabled,
|
|
25
|
-
},
|
|
26
|
-
resize: "none",
|
|
27
|
-
}));
|
|
28
3
|
|
|
29
4
|
export const useAutoResize = (value: string) => {
|
|
30
5
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
@@ -44,14 +19,12 @@ export const AutoResizingTextArea = memo(
|
|
|
44
19
|
{
|
|
45
20
|
value,
|
|
46
21
|
onChangeText,
|
|
22
|
+
className,
|
|
47
23
|
...rest
|
|
48
|
-
}:
|
|
49
|
-
React.ComponentProps<typeof TextAreaElement>,
|
|
50
|
-
"onChange" | "value"
|
|
51
|
-
> & {
|
|
24
|
+
}: {
|
|
52
25
|
onChangeText: (value: string) => void;
|
|
53
26
|
value?: string;
|
|
54
|
-
}
|
|
27
|
+
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
|
55
28
|
forwardedRef: React.ForwardedRef<HTMLTextAreaElement>
|
|
56
29
|
) {
|
|
57
30
|
const ref = useAutoResize(value || rest.placeholder || "");
|
|
@@ -71,7 +44,8 @@ export const AutoResizingTextArea = memo(
|
|
|
71
44
|
);
|
|
72
45
|
|
|
73
46
|
return (
|
|
74
|
-
<
|
|
47
|
+
<textarea
|
|
48
|
+
className={`font-sans text-heading5 font-normal text-text bg-input-background w-0 flex-1 py-1 px-1.5 border-none outline-none h-[100px] rounded-4 resize-none placeholder:text-text-disabled focus:ring-2 focus:ring-primary focus:z-10 read-only:text-text-disabled ${className ?? ""}`}
|
|
75
49
|
ref={handleRef}
|
|
76
50
|
{...rest}
|
|
77
51
|
onChange={handleChange}
|
package/src/components/Toast.tsx
CHANGED
|
@@ -1,56 +1,7 @@
|
|
|
1
1
|
import * as ToastPrimitive from '@radix-ui/react-toast';
|
|
2
2
|
import React, { ReactNode } from 'react';
|
|
3
|
-
import styled from 'styled-components';
|
|
4
3
|
import { IconButton } from './IconButton';
|
|
5
|
-
|
|
6
|
-
const ToastViewport = styled(ToastPrimitive.Viewport)({
|
|
7
|
-
position: 'fixed',
|
|
8
|
-
bottom: 0,
|
|
9
|
-
right: 0,
|
|
10
|
-
display: 'flex',
|
|
11
|
-
flexDirection: 'column',
|
|
12
|
-
padding: 20,
|
|
13
|
-
gap: 10,
|
|
14
|
-
minWidth: 200,
|
|
15
|
-
maxWidth: '100vw',
|
|
16
|
-
margin: 0,
|
|
17
|
-
listStyle: 'none',
|
|
18
|
-
zIndex: 2147483647,
|
|
19
|
-
outline: 'none',
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const ToastRoot = styled(ToastPrimitive.Root)(({ theme }) => ({
|
|
23
|
-
borderRadius: 4,
|
|
24
|
-
fontSize: 14,
|
|
25
|
-
backgroundColor: theme.colors.popover.background,
|
|
26
|
-
boxShadow: '0 2px 4px rgba(0,0,0,0.2), 0 0 12px rgba(0,0,0,0.1)',
|
|
27
|
-
color: theme.colors.textMuted,
|
|
28
|
-
|
|
29
|
-
padding: '8px 10px',
|
|
30
|
-
display: 'grid',
|
|
31
|
-
gridTemplateAreas: '"title action" "description action"',
|
|
32
|
-
gridTemplateColumns: 'auto max-content',
|
|
33
|
-
columnGap: 10,
|
|
34
|
-
alignItems: 'center',
|
|
35
|
-
}));
|
|
36
|
-
|
|
37
|
-
const ToastTitle = styled(ToastPrimitive.Title)(({ theme }) => ({
|
|
38
|
-
gridArea: 'title',
|
|
39
|
-
marginBottom: 5,
|
|
40
|
-
...theme.textStyles.label,
|
|
41
|
-
fontWeight: 'bold',
|
|
42
|
-
color: theme.colors.text,
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
const ToastDescription = styled(ToastPrimitive.Description)(({ theme }) => ({
|
|
46
|
-
gridArea: 'description',
|
|
47
|
-
...theme.textStyles.small,
|
|
48
|
-
color: theme.colors.textMuted,
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
const ToastAction = styled(ToastPrimitive.Action)({
|
|
52
|
-
gridArea: 'action',
|
|
53
|
-
});
|
|
4
|
+
import { textStyles } from './Text';
|
|
54
5
|
|
|
55
6
|
export const Toast = ({
|
|
56
7
|
title,
|
|
@@ -63,24 +14,31 @@ export const Toast = ({
|
|
|
63
14
|
children?: React.ReactNode;
|
|
64
15
|
}) => {
|
|
65
16
|
return (
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
17
|
+
<ToastPrimitive.Root
|
|
18
|
+
className="px-2 py-2.5 grid grid-cols-[auto_max-content] gap-x-2.5 items-center rounded text-sm bg-popover-background shadow-[0_2px_4px_rgba(0,0,0,0.2),0_0_12px_rgba(0,0,0,0.1)] text-text-muted"
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
{title && (
|
|
22
|
+
<ToastPrimitive.Title className={`mb-[5px] ${textStyles.label} font-bold text-text`}>
|
|
23
|
+
{title}
|
|
24
|
+
</ToastPrimitive.Title>
|
|
25
|
+
)}
|
|
26
|
+
<ToastPrimitive.Description className={`${textStyles.small} text-text-muted`}>{content}</ToastPrimitive.Description>
|
|
69
27
|
{children && (
|
|
70
|
-
<
|
|
28
|
+
<ToastPrimitive.Action asChild altText="">
|
|
71
29
|
{children}
|
|
72
|
-
</
|
|
30
|
+
</ToastPrimitive.Action>
|
|
73
31
|
)}
|
|
74
32
|
<ToastPrimitive.Close aria-label="Close" asChild>
|
|
75
33
|
<IconButton iconName="Cross1Icon" />
|
|
76
34
|
</ToastPrimitive.Close>
|
|
77
|
-
</
|
|
35
|
+
</ToastPrimitive.Root>
|
|
78
36
|
);
|
|
79
37
|
};
|
|
80
38
|
|
|
81
39
|
export const ToastProvider = ({ children }: { children: React.ReactNode }) => (
|
|
82
40
|
<ToastPrimitive.Provider>
|
|
83
41
|
{children}
|
|
84
|
-
<
|
|
42
|
+
<ToastPrimitive.Viewport className="fixed bottom-0 right-0 flex flex-col p-5 g-2.5 min-w-[200px] max-w-[100vw] m-0 list-none z-[2147483647] outline-none" />
|
|
85
43
|
</ToastPrimitive.Provider>
|
|
86
44
|
);
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
2
2
|
import React, { memo, ReactNode } from 'react';
|
|
3
|
-
import
|
|
3
|
+
import { textStyles } from './Text';
|
|
4
4
|
|
|
5
5
|
// const Arrow = styled(TooltipPrimitive.Arrow)(({ theme }) => ({
|
|
6
6
|
// fill: theme.colors.popover.background,
|
|
7
7
|
// }));
|
|
8
8
|
|
|
9
|
-
const Content = styled(TooltipPrimitive.Content)(({ theme }) => ({
|
|
10
|
-
...theme.textStyles.small,
|
|
11
|
-
color: theme.colors.text,
|
|
12
|
-
borderRadius: 3,
|
|
13
|
-
padding: `${theme.sizes.spacing.small}px ${theme.sizes.spacing.medium}px`,
|
|
14
|
-
backgroundColor: theme.colors.popover.background,
|
|
15
|
-
boxShadow: '0 2px 4px rgba(0,0,0,0.2), 0 0 12px rgba(0,0,0,0.1)',
|
|
16
|
-
border: `1px solid ${theme.colors.dividerStrong}`,
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
9
|
interface Props {
|
|
20
10
|
children: ReactNode;
|
|
21
11
|
content: ReactNode;
|
|
@@ -27,15 +17,16 @@ export const Tooltip = memo(function Tooltip({ children, content }: Props) {
|
|
|
27
17
|
<TooltipPrimitive.Root>
|
|
28
18
|
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
|
29
19
|
<TooltipPrimitive.Portal>
|
|
30
|
-
<Content
|
|
20
|
+
<TooltipPrimitive.Content
|
|
31
21
|
side="bottom"
|
|
32
22
|
align="center"
|
|
33
23
|
sideOffset={2}
|
|
34
24
|
collisionPadding={8}
|
|
25
|
+
className={`${textStyles.small} text-text rounded-[3px] py-small px-medium bg-popover-background shadow-[0_2px_4px_var(--shadow-color)_0_0_12px_var(--shadow-color)] border border-solid border-divider-strong`}
|
|
35
26
|
>
|
|
36
27
|
{content}
|
|
37
28
|
{/* <Arrow /> */}
|
|
38
|
-
</Content>
|
|
29
|
+
</TooltipPrimitive.Content>
|
|
39
30
|
</TooltipPrimitive.Portal>
|
|
40
31
|
</TooltipPrimitive.Root>
|
|
41
32
|
</TooltipPrimitive.Provider>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DesignSystemThemeProvider,
|
|
3
|
-
useDesignSystemTheme,
|
|
4
|
-
} from "@noya-app/noya-designsystem";
|
|
5
1
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
6
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
7
9
|
import {
|
|
8
10
|
ImperativePanelGroupHandle,
|
|
9
11
|
ImperativePanelHandle,
|
|
@@ -98,9 +100,17 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
98
100
|
const leftSidebarRef = useRef<ImperativePanelHandle>(null);
|
|
99
101
|
const rightSidebarRef = useRef<ImperativePanelHandle>(null);
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
const [internalLayoutState, setInternalLayoutState] =
|
|
104
|
+
useState<PanelLayoutState | null>(null);
|
|
105
|
+
const handleChangeLayoutState = useCallback(
|
|
106
|
+
(state: PanelLayoutState) => {
|
|
107
|
+
setInternalLayoutState(state);
|
|
108
|
+
onChangeLayoutState?.(state);
|
|
109
|
+
},
|
|
110
|
+
[onChangeLayoutState]
|
|
111
|
+
);
|
|
102
112
|
|
|
103
|
-
|
|
113
|
+
usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
|
|
104
114
|
|
|
105
115
|
useImperativeHandle(forwardedRef, () => ({
|
|
106
116
|
setLeftSidebarExpanded: (expanded: boolean) => {
|
|
@@ -174,7 +184,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
174
184
|
id={id}
|
|
175
185
|
className={className}
|
|
176
186
|
style={{
|
|
177
|
-
backgroundColor:
|
|
187
|
+
backgroundColor: "var(--canvas-background)",
|
|
178
188
|
display: "flex",
|
|
179
189
|
flexDirection: "row",
|
|
180
190
|
...style,
|
|
@@ -207,14 +217,16 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
207
217
|
position: "relative",
|
|
208
218
|
}}
|
|
209
219
|
>
|
|
210
|
-
{
|
|
220
|
+
{internalLayoutState?.leftSidebarCollapsed
|
|
221
|
+
? null
|
|
222
|
+
: leftPanelContent}
|
|
211
223
|
</Panel>
|
|
212
224
|
<PanelResizeHandle
|
|
213
225
|
style={{
|
|
214
226
|
cursor: "col-resize",
|
|
215
227
|
width: "1px",
|
|
216
228
|
height: "100%",
|
|
217
|
-
backgroundColor:
|
|
229
|
+
backgroundColor: "var(--divider)",
|
|
218
230
|
}}
|
|
219
231
|
/>
|
|
220
232
|
</>
|
|
@@ -239,7 +251,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
239
251
|
cursor: "col-resize",
|
|
240
252
|
width: "1px",
|
|
241
253
|
height: "100%",
|
|
242
|
-
backgroundColor:
|
|
254
|
+
backgroundColor: "var(--divider)",
|
|
243
255
|
}}
|
|
244
256
|
/>
|
|
245
257
|
<Panel
|
|
@@ -255,7 +267,9 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
255
267
|
position: "relative",
|
|
256
268
|
}}
|
|
257
269
|
>
|
|
258
|
-
{
|
|
270
|
+
{internalLayoutState?.rightSidebarCollapsed
|
|
271
|
+
? null
|
|
272
|
+
: rightPanelContent}
|
|
259
273
|
</Panel>
|
|
260
274
|
</>
|
|
261
275
|
)}
|
|
@@ -268,9 +282,5 @@ export const WorkspaceLayout = forwardRef(function WorkspaceLayout(
|
|
|
268
282
|
props: Props,
|
|
269
283
|
forwardedRef: React.ForwardedRef<IWorkspaceLayout>
|
|
270
284
|
) {
|
|
271
|
-
return
|
|
272
|
-
<DesignSystemThemeProvider>
|
|
273
|
-
<WorkspaceLayoutWithTheme {...props} ref={forwardedRef} />
|
|
274
|
-
</DesignSystemThemeProvider>
|
|
275
|
-
);
|
|
285
|
+
return <WorkspaceLayoutWithTheme {...props} ref={forwardedRef} />;
|
|
276
286
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getShortcutDisplayParts } from "@noya-app/noya-keymap";
|
|
2
2
|
import React, { memo, ReactNode } from "react";
|
|
3
|
-
import styled, { CSSObject } from "styled-components";
|
|
4
3
|
import { useDesignSystemConfiguration } from "../../contexts/DesignSystemConfiguration";
|
|
5
|
-
import { Theme } from "../../theme";
|
|
6
4
|
import withSeparatorElements from "../../utils/withSeparatorElements";
|
|
7
5
|
import { IconName } from "../Icons";
|
|
6
|
+
import { cn } from "../../utils/tailwind";
|
|
7
|
+
import { textStyles } from "../Text";
|
|
8
8
|
|
|
9
9
|
export const SEPARATOR_ITEM = "separator";
|
|
10
10
|
|
|
@@ -77,76 +77,39 @@ export type MenuItem<T extends string> =
|
|
|
77
77
|
export type ExtractMenuItemType<T> =
|
|
78
78
|
T extends RegularMenuItem<infer U> ? U : never;
|
|
79
79
|
|
|
80
|
-
export const CHECKBOX_WIDTH =
|
|
81
|
-
export const CHECKBOX_RIGHT_INSET =
|
|
80
|
+
export const CHECKBOX_WIDTH = 16;
|
|
81
|
+
export const CHECKBOX_RIGHT_INSET = 8;
|
|
82
82
|
|
|
83
83
|
export const styles = {
|
|
84
|
-
separatorStyle:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
flex
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
"&:active": {
|
|
116
|
-
background: theme.colors.primaryLight,
|
|
117
|
-
},
|
|
118
|
-
display: "flex",
|
|
119
|
-
alignItems: "center",
|
|
120
|
-
}),
|
|
121
|
-
|
|
122
|
-
itemIndicatorStyle: {
|
|
123
|
-
display: "flex",
|
|
124
|
-
alignItems: "center",
|
|
125
|
-
left: `-${CHECKBOX_WIDTH / 2}px`,
|
|
126
|
-
position: "relative",
|
|
127
|
-
marginRight: `-${CHECKBOX_RIGHT_INSET}px`,
|
|
128
|
-
} as CSSObject,
|
|
129
|
-
|
|
130
|
-
contentStyle: ({
|
|
131
|
-
theme,
|
|
132
|
-
scrollable,
|
|
133
|
-
}: {
|
|
134
|
-
theme: Theme;
|
|
135
|
-
scrollable?: boolean;
|
|
136
|
-
}): CSSObject => ({
|
|
137
|
-
borderRadius: 4,
|
|
138
|
-
backgroundColor: theme.colors.popover.background,
|
|
139
|
-
color: theme.colors.text,
|
|
140
|
-
boxShadow: "0 2px 4px rgba(0,0,0,0.2), 0 0 12px rgba(0,0,0,0.1)",
|
|
141
|
-
padding: "4px",
|
|
142
|
-
border: `1px solid ${theme.colors.popover.divider}`,
|
|
143
|
-
zIndex: 1000,
|
|
144
|
-
...(scrollable && {
|
|
145
|
-
height: "100%",
|
|
146
|
-
maxHeight: "calc(100vh - 80px)",
|
|
147
|
-
overflow: "hidden auto",
|
|
148
|
-
}),
|
|
149
|
-
}),
|
|
84
|
+
separatorStyle: "h-px bg-divider mx-[-4px] my-1",
|
|
85
|
+
|
|
86
|
+
itemStyle: ({ disabled }: { disabled?: boolean }) => `
|
|
87
|
+
flex-none select-none cursor-pointer rounded
|
|
88
|
+
p-[6px_8px]
|
|
89
|
+
flex items-center
|
|
90
|
+
font-sans text-button font-medium
|
|
91
|
+
${disabled ? "text-text-disabled" : ""}
|
|
92
|
+
focus:outline-none focus:text-white focus:bg-primary
|
|
93
|
+
focus:kbd:text-white
|
|
94
|
+
active:bg-primary-light
|
|
95
|
+
`,
|
|
96
|
+
|
|
97
|
+
itemIndicatorStyle: `
|
|
98
|
+
flex items-center
|
|
99
|
+
relative
|
|
100
|
+
-left-2.5
|
|
101
|
+
-mr-2
|
|
102
|
+
`,
|
|
103
|
+
|
|
104
|
+
contentStyle: `
|
|
105
|
+
rounded
|
|
106
|
+
bg-popover-background
|
|
107
|
+
text-text
|
|
108
|
+
shadow-[0_2px_4px_rgba(0,0,0,0.2),_0_0_12px_rgba(0,0,0,0.1)]
|
|
109
|
+
p-1
|
|
110
|
+
border border-popover-divider
|
|
111
|
+
z-50
|
|
112
|
+
`,
|
|
150
113
|
};
|
|
151
114
|
|
|
152
115
|
function getKeyboardShortcuts<T extends string>(
|
|
@@ -172,18 +135,9 @@ export function getKeyboardShortcutsForMenuItems<T extends string>(
|
|
|
172
135
|
);
|
|
173
136
|
}
|
|
174
137
|
|
|
175
|
-
const ShortcutElement =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
({ theme, $fixedWidth }): CSSObject => ({
|
|
179
|
-
...theme.textStyles.small,
|
|
180
|
-
color: theme.colors.textDisabled,
|
|
181
|
-
...($fixedWidth && {
|
|
182
|
-
width: "0.9rem",
|
|
183
|
-
textAlign: "center",
|
|
184
|
-
}),
|
|
185
|
-
})
|
|
186
|
-
);
|
|
138
|
+
const ShortcutElement = ({children, fixedWidth}: {children?: React.ReactNode; fixedWidth?: boolean}) => (
|
|
139
|
+
<kbd className={cn(textStyles.small, "text-text-disabled", fixedWidth && "w-[0.9rem] text-center")}>{children}</kbd>
|
|
140
|
+
)
|
|
187
141
|
|
|
188
142
|
export const KeyboardShortcut = memo(function KeyboardShortcut({
|
|
189
143
|
shortcut,
|
|
@@ -197,7 +151,7 @@ export const KeyboardShortcut = memo(function KeyboardShortcut({
|
|
|
197
151
|
const keyElements = keys.map((key) => (
|
|
198
152
|
<ShortcutElement
|
|
199
153
|
key={key}
|
|
200
|
-
|
|
154
|
+
fixedWidth={platform === "mac" && key.length === 1}
|
|
201
155
|
>
|
|
202
156
|
{key}
|
|
203
157
|
</ShortcutElement>
|
|
@@ -8,41 +8,10 @@ import React, {
|
|
|
8
8
|
useMemo,
|
|
9
9
|
useState,
|
|
10
10
|
} from "react";
|
|
11
|
-
import { ThemeProvider, useTheme } from "styled-components";
|
|
12
11
|
import { ToastProvider } from "../components/Toast";
|
|
13
|
-
import { Theme } from "../theme";
|
|
14
|
-
import * as darkTheme from "../theme/dark";
|
|
15
|
-
import * as lightTheme from "../theme/light";
|
|
16
12
|
import { DialogProvider } from "./DialogContext";
|
|
17
13
|
import { FloatingWindowProvider } from "./FloatingWindowContext";
|
|
18
14
|
|
|
19
|
-
export const DesignSystemThemeProvider = memo(
|
|
20
|
-
function DesignSystemThemeProvider({
|
|
21
|
-
children,
|
|
22
|
-
theme,
|
|
23
|
-
}: {
|
|
24
|
-
children: ReactNode;
|
|
25
|
-
theme?: Theme;
|
|
26
|
-
}) {
|
|
27
|
-
let parentTheme: Theme | undefined;
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
31
|
-
parentTheme = useTheme();
|
|
32
|
-
} catch (e) {
|
|
33
|
-
// console.error(e);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (theme) {
|
|
37
|
-
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
|
|
38
|
-
} else if (parentTheme) {
|
|
39
|
-
return children;
|
|
40
|
-
} else {
|
|
41
|
-
return <ThemeProvider theme={lightTheme}>{children}</ThemeProvider>;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
|
|
46
15
|
export type DesignSystemConfigurationContextValue = {
|
|
47
16
|
platform: PlatformName;
|
|
48
17
|
};
|
|
@@ -55,11 +24,9 @@ const DesignSystemConfigurationContext =
|
|
|
55
24
|
export const DesignSystemConfigurationProvider = memo(
|
|
56
25
|
function DesignSystemConfigurationProvider({
|
|
57
26
|
children,
|
|
58
|
-
theme,
|
|
59
27
|
platform,
|
|
60
28
|
}: {
|
|
61
29
|
children: ReactNode;
|
|
62
|
-
theme?: Theme | "light" | "dark";
|
|
63
30
|
platform?: PlatformName;
|
|
64
31
|
}) {
|
|
65
32
|
const [internalPlatform, setInternalPlatform] = useState<PlatformName>(
|
|
@@ -79,22 +46,13 @@ export const DesignSystemConfigurationProvider = memo(
|
|
|
79
46
|
[platform, internalPlatform]
|
|
80
47
|
);
|
|
81
48
|
|
|
82
|
-
const resolvedTheme =
|
|
83
|
-
theme === "light"
|
|
84
|
-
? lightTheme
|
|
85
|
-
: theme === "dark"
|
|
86
|
-
? darkTheme
|
|
87
|
-
: theme ?? lightTheme;
|
|
88
|
-
|
|
89
49
|
return (
|
|
90
50
|
<DesignSystemConfigurationContext.Provider value={contextValue}>
|
|
91
|
-
<ThemeProvider theme={resolvedTheme}>
|
|
92
51
|
<DialogProvider>
|
|
93
52
|
<ToastProvider>
|
|
94
53
|
<FloatingWindowProvider>{children}</FloatingWindowProvider>
|
|
95
54
|
</ToastProvider>
|
|
96
55
|
</DialogProvider>
|
|
97
|
-
</ThemeProvider>
|
|
98
56
|
</DesignSystemConfigurationContext.Provider>
|
|
99
57
|
);
|
|
100
58
|
}
|
|
@@ -102,8 +60,4 @@ export const DesignSystemConfigurationProvider = memo(
|
|
|
102
60
|
|
|
103
61
|
export function useDesignSystemConfiguration(): DesignSystemConfigurationContextValue {
|
|
104
62
|
return useContext(DesignSystemConfigurationContext);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function useDesignSystemTheme() {
|
|
108
|
-
return useTheme();
|
|
109
|
-
}
|
|
63
|
+
}
|