@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.
Files changed (64) hide show
  1. package/.turbo/turbo-build.log +20 -12
  2. package/.turbo/turbo-lint.log +15 -1
  3. package/CHANGELOG.md +17 -0
  4. package/README.md +13 -1
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +238 -627
  7. package/dist/index.js +4259 -2862
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +4159 -2764
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +17 -7
  12. package/src/components/ActivityIndicator.tsx +4 -36
  13. package/src/components/Avatar.tsx +63 -62
  14. package/src/components/Button.tsx +53 -170
  15. package/src/components/Chip.tsx +117 -150
  16. package/src/components/ContextMenu.tsx +13 -35
  17. package/src/components/Dialog.tsx +66 -54
  18. package/src/components/Divider.tsx +31 -41
  19. package/src/components/DraggableMenuButton.tsx +29 -30
  20. package/src/components/DropdownMenu.tsx +30 -40
  21. package/src/components/FillInputField.tsx +16 -26
  22. package/src/components/FillPreviewBackground.tsx +18 -22
  23. package/src/components/FloatingWindow.tsx +4 -7
  24. package/src/components/GridView.tsx +70 -200
  25. package/src/components/IconButton.tsx +1 -5
  26. package/src/components/InputField.tsx +258 -234
  27. package/src/components/InputFieldWithCompletions.tsx +20 -27
  28. package/src/components/InspectorContainer.tsx +4 -9
  29. package/src/components/InspectorPrimitives.tsx +135 -109
  30. package/src/components/Label.tsx +5 -36
  31. package/src/components/LabeledElementView.tsx +5 -26
  32. package/src/components/ListView.tsx +239 -167
  33. package/src/components/Popover.tsx +15 -39
  34. package/src/components/Progress.tsx +21 -44
  35. package/src/components/RadioGroup.tsx +6 -71
  36. package/src/components/ScrollArea.tsx +11 -39
  37. package/src/components/SelectMenu.tsx +72 -32
  38. package/src/components/Slider.tsx +7 -43
  39. package/src/components/Spacer.tsx +6 -18
  40. package/src/components/Switch.tsx +4 -42
  41. package/src/components/Text.tsx +31 -66
  42. package/src/components/TextArea.tsx +5 -31
  43. package/src/components/Toast.tsx +15 -57
  44. package/src/components/Tooltip.tsx +4 -13
  45. package/src/components/WorkspaceLayout.tsx +27 -17
  46. package/src/components/internal/Menu.tsx +37 -83
  47. package/src/contexts/DesignSystemConfiguration.tsx +1 -47
  48. package/src/contexts/DialogContext.tsx +2 -10
  49. package/src/hooks/useDarkMode.ts +14 -0
  50. package/src/index.css +108 -0
  51. package/src/index.tsx +4 -5
  52. package/src/theme/index.ts +4 -16
  53. package/src/utils/tailwind.ts +17 -0
  54. package/tailwind.config.ts +223 -0
  55. package/tailwind.d.ts +11 -0
  56. package/tsconfig.json +4 -1
  57. package/tsup.config.ts +16 -0
  58. package/dist/index.d.mts +0 -1455
  59. package/src/components/Grid.tsx +0 -54
  60. package/src/components/Select.tsx +0 -183
  61. package/src/components/Stack.tsx +0 -155
  62. package/src/theme/dark.ts +0 -45
  63. package/src/theme/light.ts +0 -226
  64. package/src/utils/breakpoints.ts +0 -45
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "@noya-app/noya-designsystem",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
7
+ "style": "./dist/index.css",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js"
12
+ },
13
+ "./index.css": "./dist/index.css"
14
+ },
7
15
  "scripts": {
8
- "build": "tsup src/index.tsx --format cjs,esm --dts --sourcemap",
16
+ "build:css": "tailwindcss -i ./src/index.css -o ./dist/index.css",
17
+ "build": "tsup",
9
18
  "dev": "npm run build -- --watch",
10
19
  "lint": "eslint . --max-warnings 0"
11
20
  },
@@ -15,7 +24,7 @@
15
24
  "@dnd-kit/sortable": "4.0.0",
16
25
  "@noya-app/noya-colorpicker": "0.1.11",
17
26
  "@noya-app/noya-utils": "0.1.2",
18
- "@noya-app/noya-geometry": "0.1.4",
27
+ "@noya-app/noya-geometry": "0.1.5",
19
28
  "@noya-app/noya-icons": "0.1.4",
20
29
  "@noya-app/noya-keymap": "0.1.2",
21
30
  "@radix-ui/primitive": "^1.0.0",
@@ -46,13 +55,14 @@
46
55
  "@types/react-dom": "*",
47
56
  "@types/react-virtualized": "^9.21.21",
48
57
  "@types/react-window": "^1.8.5",
58
+ "esbuild-plugin-react-virtualized": "1.0.4",
59
+ "esbuild-plugin-tailwindcss": "^1.2.1",
49
60
  "react-virtualized": "9.22.5",
50
- "esbuild-plugin-react-virtualized": "1.0.4"
61
+ "tailwind-merge": "^2.5.4",
62
+ "tailwindcss": "^3.4.14"
51
63
  },
52
64
  "peerDependencies": {
53
65
  "react": "*",
54
- "react-dom": "*",
55
- "styled-components": "6.1.12",
56
- "stylis": "4.3.2"
66
+ "react-dom": "*"
57
67
  }
58
68
  }
@@ -1,5 +1,5 @@
1
1
  import React, { memo } from "react";
2
- import styled, { keyframes } from "styled-components";
2
+ import { cn } from "../utils/tailwind";
3
3
 
4
4
  interface Props {
5
5
  size?: number;
@@ -8,38 +8,6 @@ interface Props {
8
8
  trackColor?: string;
9
9
  }
10
10
 
11
- interface SpinnerProps {
12
- $opacity: number;
13
- }
14
-
15
- interface SpinnerCircleProps {
16
- $size: number;
17
- $color: string;
18
- $trackColor: string;
19
- }
20
-
21
- const spin = keyframes`
22
- 0% { transform: rotate(0deg); }
23
- 100% { transform: rotate(360deg); }
24
- `;
25
-
26
- const Spinner = styled.div<SpinnerProps>`
27
- display: flex;
28
- justify-content: center;
29
- align-items: center;
30
- opacity: ${({ $opacity }: SpinnerProps) => $opacity};
31
- `;
32
-
33
- // Use css syntax to support keyframes
34
- const SpinnerCircle = styled.div<SpinnerCircleProps>`
35
- border: 2px solid ${({ $trackColor }) => $trackColor};
36
- border-top: 2px solid ${({ $color }) => $color};
37
- border-radius: 50%;
38
- width: ${({ $size }) => `${$size}px`};
39
- height: ${({ $size }) => `${$size}px`};
40
- animation: ${spin} 1s linear infinite;
41
- `;
42
-
43
11
  export const ActivityIndicator = memo(function ActivityIndicator({
44
12
  size = 16,
45
13
  opacity = 1,
@@ -47,8 +15,8 @@ export const ActivityIndicator = memo(function ActivityIndicator({
47
15
  trackColor = "rgba(0, 0, 0, 0.1)",
48
16
  }: Props) {
49
17
  return (
50
- <Spinner $opacity={opacity}>
51
- <SpinnerCircle $size={size} $color={color} $trackColor={trackColor} />
52
- </Spinner>
18
+ <div className={cn("flex justify-center items-center", `opacity-[${opacity}]`)}>
19
+ <div className={cn("animate-spin", `border-[2px_solid_${trackColor}] border-t-[2px_solid_${color}] rounded-[50%] w-[${size}px] h-[${size}px]`)} />
20
+ </div>
53
21
  );
54
22
  });
@@ -1,52 +1,63 @@
1
- import * as AvatarPrimitive from "@radix-ui/react-avatar";
2
1
  import React, { forwardRef } from "react";
3
- import styled from "styled-components";
4
- import { Stack } from "./Stack";
5
-
6
- const AvatarRoot = styled(AvatarPrimitive.Root)<{
7
- size: number;
8
- overflow: number;
9
- }>(({ theme, size, overflow }) => ({
10
- display: "inline-flex",
11
- alignItems: "center",
12
- justifyContent: "center",
13
- verticalAlign: "middle",
14
- overflow: "hidden",
15
- userSelect: "none",
16
- width: size,
17
- height: size,
18
- borderRadius: "100%",
19
- backgroundColor: theme.colors.inputBackground,
20
- ...(overflow && {
21
- margin: `-${overflow}px`,
22
- }),
2
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
23
3
 
24
- "&:hover": {
25
- boxShadow: `0 0 0 2px ${theme.colors.sidebar.background}`,
26
- opacity: 0.9,
27
- },
28
- }));
4
+ const AvatarRoot = React.forwardRef<
5
+ React.ElementRef<typeof AvatarPrimitive.Root>,
6
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & {
7
+ size: number;
8
+ overflow: number;
9
+ }
10
+ >(({ className, size, overflow, ...props }, ref) => (
11
+ <AvatarPrimitive.Root
12
+ ref={ref}
13
+ className={`
14
+ inline-flex items-center justify-center
15
+ align-middle overflow-hidden select-none
16
+ w-[${size}px] h-[${size}px]
17
+ rounded-full bg-input-background
18
+ ${overflow ? `m-[-${overflow}px]` : ""}
19
+ hover:shadow-[0_0_0_2px_var(--sidebar-background)] hover:opacity-90
20
+ ${className ?? ""}
21
+ `}
22
+ {...props}
23
+ />
24
+ ));
29
25
 
30
- const AvatarImage = styled(AvatarPrimitive.Image)({
31
- width: "100%",
32
- height: "100%",
33
- objectFit: "cover",
34
- borderRadius: "inherit",
35
- });
26
+ const AvatarImage = React.forwardRef<
27
+ React.ElementRef<typeof AvatarPrimitive.Image>,
28
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
29
+ >(({ className, ...props }, ref) => (
30
+ <AvatarPrimitive.Image
31
+ ref={ref}
32
+ className={`
33
+ w-full h-full
34
+ object-cover
35
+ rounded-inherit
36
+ ${className ?? ""}
37
+ `}
38
+ {...props}
39
+ />
40
+ ));
36
41
 
37
- const AvatarFallback = styled(AvatarPrimitive.Fallback)<{
38
- size: number;
39
- }>(({ theme, size }) => ({
40
- fontSize: "0.8rem",
41
- fontWeight: 500,
42
- width: "100%",
43
- height: "100%",
44
- display: "flex",
45
- alignItems: "center",
46
- justifyContent: "center",
47
- color: "white",
48
- lineHeight: `${size}px`,
49
- }));
42
+ const AvatarFallback = React.forwardRef<
43
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
44
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & {
45
+ size: number;
46
+ }
47
+ >(({ className, size, ...props }, ref) => (
48
+ <AvatarPrimitive.Fallback
49
+ ref={ref}
50
+ className={`
51
+ text-[0.8rem] font-medium
52
+ w-full h-full
53
+ flex items-center justify-center
54
+ text-white
55
+ leading-[${size}px]
56
+ ${className ?? ""}
57
+ `}
58
+ {...props}
59
+ />
60
+ ));
50
61
 
51
62
  export const Avatar = forwardRef(function Avatar(
52
63
  {
@@ -75,19 +86,6 @@ export const Avatar = forwardRef(function Avatar(
75
86
  );
76
87
  });
77
88
 
78
- const AvatarStackItemWrapper = styled.div<{
79
- $size: number;
80
- }>(({ $size, theme }) => ({
81
- position: "relative",
82
- width: $size,
83
- height: $size,
84
- marginLeft: "-8px",
85
- // outline: `2px solid ${theme.colors.sidebar.background}`,
86
- borderRadius: "50%",
87
- clipPath: `circle(50%)`,
88
- overflow: "hidden",
89
- }));
90
-
91
89
  export function AvatarStack({
92
90
  size = 19,
93
91
  children,
@@ -100,16 +98,19 @@ export function AvatarStack({
100
98
  });
101
99
 
102
100
  return (
103
- <Stack.H>
101
+ <div className="flex">
104
102
  {childrenArray.map((child, index) => {
105
103
  if (index === 0) return child;
106
104
 
107
105
  return (
108
- <AvatarStackItemWrapper $size={size} key={index}>
106
+ <div
107
+ className={`relative w-[${size}px] h-[${size}px] -ml-2 rounded-full overflow-hidden [clip-path:circle(50%)]`}
108
+ key={index}
109
+ >
109
110
  {child}
110
- </AvatarStackItemWrapper>
111
+ </div>
111
112
  );
112
113
  })}
113
- </Stack.H>
114
+ </div>
114
115
  );
115
116
  }
@@ -5,7 +5,6 @@ import React, {
5
5
  ReactNode,
6
6
  useCallback,
7
7
  } from "react";
8
- import styled from "styled-components";
9
8
  import { Tooltip } from "./Tooltip";
10
9
 
11
10
  type ButtonVariant =
@@ -19,167 +18,37 @@ type ButtonVariant =
19
18
  | "floating"
20
19
  | "none";
21
20
 
22
- type ButtonSize = "normal" | "large";
21
+ type ButtonSize = "small" | "normal" | "large" | "floating";
23
22
 
24
- /* ----------------------------------------------------------------------------
25
- * Element
26
- * ------------------------------------------------------------------------- */
23
+ const variantStyles: Record<ButtonVariant, string> = {
24
+ normal:
25
+ "bg-input-background text-text hover:bg-input-background-light active:bg-active-background min-w-[31px]",
26
+ primary: "bg-primary text-white hover:bg-primary-light active:bg-primary",
27
+ primaryGradient:
28
+ "bg-gradient-to-r from-primary to-primary-light text-text hover:bg-primary-light",
29
+ secondary:
30
+ "bg-secondary text-white hover:bg-secondary-light active:bg-secondary",
31
+ secondaryBright: "bg-[#0ab557] text-white hover:opacity-80 active:opacity-90",
32
+ white: "bg-white hover:opacity-80 active:opacity-90",
33
+ thin: "bg-transparent text-text hover:bg-input-background-light",
34
+ floating:
35
+ "bg-white text-text shadow-[0_1px_2px_rgba(0,0,0,0.1)] hover:opacity-80 active:opacity-90",
36
+ none: "bg-transparent text-text hover:bg-input-background-light",
37
+ };
27
38
 
28
- export const ButtonElement = styled.button<{
29
- $active: boolean;
30
- $variant: ButtonVariant;
31
- $size: ButtonSize;
32
- $flex?: CSSProperties["flex"];
33
- $defaultBackground?: string;
34
- }>(
35
- ({
36
- theme,
37
- $active,
38
- disabled,
39
- $variant,
40
- $size,
41
- $flex,
42
- $defaultBackground = theme.colors.inputBackground,
43
- }) => ({
44
- ...($size === "large"
45
- ? theme.textStyles.heading4
46
- : theme.textStyles.button),
47
- textDecoration: "none",
48
- lineHeight: "1",
49
- flex: $flex ?? "0 0 auto",
50
- position: "relative",
51
- border: "0",
52
- outline: "none",
53
- WebkitAppRegion: "no-drag",
54
- userSelect: "none",
55
- minWidth: $variant === "normal" ? "31px" : undefined,
56
- textAlign: "left",
57
- borderRadius: "4px",
58
- paddingTop: $variant === "none" ? "0px" : "4px",
59
- paddingRight:
60
- $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "6px",
61
- paddingBottom: $variant === "none" ? "0px" : "4px",
62
- paddingLeft:
63
- $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "6px",
64
- ...($size === "large" && {
65
- paddingTop: "12px",
66
- paddingRight: "16px",
67
- paddingBottom: "12px",
68
- paddingLeft: "16px",
69
- }),
70
- background: $active
71
- ? theme.colors.primary
72
- : $variant === "primaryGradient"
73
- ? `linear-gradient(90deg, ${theme.colors.primary}, ${theme.colors.primaryLight})`
74
- : $variant === "none" || $variant === "thin"
75
- ? "transparent"
76
- : $defaultBackground,
77
- color: $active ? "white" : theme.colors.text,
78
- opacity: disabled ? 0.25 : 1,
79
- "&:focus": {
80
- outline: `2px solid ${theme.colors.primary}`,
81
- boxShadow: `0 0 0 1px ${theme.colors.popover.background} inset`,
82
- },
83
- "&:hover": {
84
- background:
85
- $variant === "primaryGradient" || $active
86
- ? theme.colors.primaryLight
87
- : theme.colors.inputBackgroundLight,
88
- },
89
- "&:active": {
90
- background:
91
- $variant === "primaryGradient" || $active
92
- ? theme.colors.primary
93
- : theme.colors.activeBackground,
94
- },
95
- ...($variant === "primary" && {
96
- background: theme.colors.primary,
97
- color: "white",
98
- "&:hover": {
99
- background: theme.colors.primaryLight,
100
- },
101
- "&:active": {
102
- background: theme.colors.primary,
103
- },
104
- }),
105
- ...($variant === "secondary" && {
106
- background: theme.colors.secondary,
107
- color: "white",
108
- "&:hover": {
109
- background: theme.colors.secondaryLight,
110
- },
111
- "&:active": {
112
- background: theme.colors.secondary,
113
- },
114
- }),
115
- ...($variant === "secondaryBright" && {
116
- background: "#0ab557",
117
- color: "white",
118
- "&:hover": {
119
- opacity: 0.8,
120
- },
121
- "&:active": {
122
- opacity: 0.9,
123
- },
124
- }),
125
- ...($variant === "white" && {
126
- background: "white",
127
- "&:hover": {
128
- opacity: 0.8,
129
- },
130
- "&:active": {
131
- opacity: 0.9,
132
- },
133
- }),
134
- ...($variant === "floating" && {
135
- background: "white",
136
- color: theme.colors.text,
137
- boxShadow: "0 1px 2px rgba(0, 0, 0, 0.1)",
138
- fontSize: "12px",
139
- padding: "0px 4px",
140
- "&:hover": {
141
- opacity: 0.8,
142
- },
143
- "&:active": {
144
- opacity: 0.9,
145
- },
146
- }),
147
- display: "flex",
148
- alignItems: "center",
149
- justifyContent: "center",
150
-
151
- "& *": {
152
- pointerEvents: "none",
153
- },
154
- })
155
- );
156
-
157
- /* ----------------------------------------------------------------------------
158
- * Content
159
- * ------------------------------------------------------------------------- */
160
-
161
- const ButtonContent = styled.span(({ theme }) => ({
162
- // Line height of small text - maybe figure out better way to ensure
163
- // icons don't have a smaller height
164
- minHeight: "19px",
165
- display: "flex",
166
- alignItems: "center",
167
- flex: "1",
168
- justifyContent: "center",
169
-
170
- // Helps with alignment with the default small text
171
- lineHeight: "15px",
172
- }));
173
-
174
- /* ----------------------------------------------------------------------------
175
- * Root
176
- * ------------------------------------------------------------------------- */
39
+ const sizeStyles: Record<ButtonSize | "thin" | "none", string> = {
40
+ small: "px-[2px] font-sans text-[10px] font-medium",
41
+ normal: "px-[6px] py-1 font-sans text-button font-medium",
42
+ large: "p-3 px-4 font-sans text-heading4 font-medium",
43
+ thin: "px-[1px] py-1 font-sans text-button font-medium",
44
+ floating: "px-1 py-0 font-sans text-[12px] font-medium",
45
+ none: "py-0 px-0",
46
+ };
177
47
 
178
48
  export interface ButtonRootProps {
179
49
  id?: string;
180
50
  className?: string;
181
51
  style?: CSSProperties;
182
- flex?: CSSProperties["flex"];
183
52
  tabIndex?: number;
184
53
  children: ReactNode;
185
54
  active?: boolean;
@@ -187,8 +56,8 @@ export interface ButtonRootProps {
187
56
  variant?: ButtonVariant;
188
57
  size?: ButtonSize;
189
58
  tooltip?: ReactNode;
190
- onClick?: (event: React.MouseEvent) => void;
191
- onPointerDown?: (event: React.PointerEvent) => void;
59
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
60
+ onPointerDown?: (event: React.PointerEvent<HTMLButtonElement>) => void;
192
61
  contentStyle?: CSSProperties;
193
62
  defaultBackground?: string;
194
63
  as?: React.ElementType;
@@ -203,7 +72,6 @@ export const Button = forwardRef(function Button(
203
72
  id,
204
73
  className,
205
74
  style,
206
- flex,
207
75
  tabIndex,
208
76
  tooltip,
209
77
  active = false,
@@ -211,35 +79,48 @@ export const Button = forwardRef(function Button(
211
79
  variant = "normal",
212
80
  size = "normal",
213
81
  contentStyle,
214
- defaultBackground,
215
82
  onClick,
216
83
  children,
217
- ...rest // Propagate any other props so this component works as a Slot
84
+ as: Component = "button",
85
+ ...rest
218
86
  }: ButtonRootProps,
219
87
  forwardedRef: ForwardedRef<HTMLButtonElement>
220
88
  ) {
221
89
  const buttonElement = (
222
- <ButtonElement
90
+ <Component
223
91
  ref={forwardedRef}
224
92
  id={id}
225
- className={className}
93
+ className={`no-underline leading-[1] relative border-0 outline-none select-none text-left rounded flex items-center justify-center [&>*]:pointer-events-none [-webkit-app-region:no-drag] focus:ring-2 focus:ring-primary focus:z-10 focus:shadow-[0_0_0_1px_var(--popover-background)_inset] ${disabled ? "opacity-25" : ""} ${!className?.includes("flex") ? "flex-none" : ""} ${
94
+ active
95
+ ? "bg-primary text-white hover:bg-primary-light active:bg-primary"
96
+ : variantStyles[variant]
97
+ } ${
98
+ sizeStyles[
99
+ variant === "thin"
100
+ ? "thin"
101
+ : variant === "floating" && size !== "small"
102
+ ? "floating"
103
+ : variant === "none"
104
+ ? "none"
105
+ : size
106
+ ]
107
+ } ${className ?? ""}`}
226
108
  style={style}
227
- $flex={flex}
228
109
  tabIndex={tabIndex}
229
- $active={active}
230
110
  disabled={disabled}
231
- $variant={variant}
232
- $size={size}
233
- $defaultBackground={defaultBackground}
234
111
  onClick={onClick}
235
- // Prevent double clicking a button from triggering any callbacks in ancestors
236
112
  onDoubleClick={useCallback((event: React.MouseEvent) => {
237
113
  event.stopPropagation();
238
114
  }, [])}
239
115
  {...rest}
240
116
  >
241
- <ButtonContent style={contentStyle}>{children}</ButtonContent>
242
- </ButtonElement>
117
+ <span
118
+ className="min-h-[19px] flex items-center flex-1 justify-center leading-[15px]"
119
+ style={contentStyle}
120
+ >
121
+ {children}
122
+ </span>
123
+ </Component>
243
124
  );
244
125
 
245
126
  return tooltip ? (
@@ -248,3 +129,5 @@ export const Button = forwardRef(function Button(
248
129
  buttonElement
249
130
  );
250
131
  });
132
+
133
+ export default Button;