@noya-app/noya-designsystem 0.1.31 → 0.1.33

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 (61) hide show
  1. package/.turbo/turbo-build.log +20 -12
  2. package/.turbo/turbo-lint.log +2 -1
  3. package/CHANGELOG.md +14 -0
  4. package/README.md +13 -1
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +132 -509
  7. package/dist/index.js +4167 -2716
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +4097 -2643
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +15 -6
  12. package/src/components/ActivityIndicator.tsx +4 -36
  13. package/src/components/Avatar.tsx +63 -62
  14. package/src/components/Button.tsx +53 -172
  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 +191 -194
  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 +31 -48
  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 +4 -14
  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 +3 -4
  52. package/src/theme/index.ts +4 -16
  53. package/src/utils/tailwind.ts +17 -0
  54. package/tailwind.config.ts +106 -166
  55. package/tsup.config.ts +16 -0
  56. package/dist/index.d.mts +0 -1443
  57. package/src/components/Grid.tsx +0 -54
  58. package/src/components/Stack.tsx +0 -164
  59. package/src/theme/dark.ts +0 -45
  60. package/src/theme/light.ts +0 -226
  61. 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.31",
3
+ "version": "0.1.33",
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
  },
@@ -13,7 +22,7 @@
13
22
  "@dnd-kit/core": "3.1.1",
14
23
  "@dnd-kit/modifiers": "3.0.0",
15
24
  "@dnd-kit/sortable": "4.0.0",
16
- "@noya-app/noya-colorpicker": "0.1.11",
25
+ "@noya-app/noya-colorpicker": "0.1.12",
17
26
  "@noya-app/noya-utils": "0.1.2",
18
27
  "@noya-app/noya-geometry": "0.1.5",
19
28
  "@noya-app/noya-icons": "0.1.4",
@@ -47,13 +56,13 @@
47
56
  "@types/react-virtualized": "^9.21.21",
48
57
  "@types/react-window": "^1.8.5",
49
58
  "esbuild-plugin-react-virtualized": "1.0.4",
59
+ "esbuild-plugin-tailwindcss": "^1.2.1",
50
60
  "react-virtualized": "9.22.5",
61
+ "tailwind-merge": "^2.5.4",
51
62
  "tailwindcss": "^3.4.14"
52
63
  },
53
64
  "peerDependencies": {
54
65
  "react": "*",
55
- "react-dom": "*",
56
- "styled-components": "6.1.12",
57
- "stylis": "4.3.2"
66
+ "react-dom": "*"
58
67
  }
59
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,178 +18,46 @@ type ButtonVariant =
19
18
  | "floating"
20
19
  | "none";
21
20
 
22
- type ButtonSize = "small" | "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: $size === "small" ? "10px" : "12px",
139
- padding: $size === "small" ? "0px 2px" : "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;
186
55
  disabled?: boolean;
187
- /** @default normal */
188
56
  variant?: ButtonVariant;
189
- /** @default normal */
190
57
  size?: ButtonSize;
191
58
  tooltip?: ReactNode;
192
- onClick?: (event: React.MouseEvent) => void;
193
- onPointerDown?: (event: React.PointerEvent) => void;
59
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
60
+ onPointerDown?: (event: React.PointerEvent<HTMLButtonElement>) => void;
194
61
  contentStyle?: CSSProperties;
195
62
  defaultBackground?: string;
196
63
  as?: React.ElementType;
@@ -205,7 +72,6 @@ export const Button = forwardRef(function Button(
205
72
  id,
206
73
  className,
207
74
  style,
208
- flex,
209
75
  tabIndex,
210
76
  tooltip,
211
77
  active = false,
@@ -213,35 +79,48 @@ export const Button = forwardRef(function Button(
213
79
  variant = "normal",
214
80
  size = "normal",
215
81
  contentStyle,
216
- defaultBackground,
217
82
  onClick,
218
83
  children,
219
- ...rest // Propagate any other props so this component works as a Slot
84
+ as: Component = "button",
85
+ ...rest
220
86
  }: ButtonRootProps,
221
87
  forwardedRef: ForwardedRef<HTMLButtonElement>
222
88
  ) {
223
89
  const buttonElement = (
224
- <ButtonElement
90
+ <Component
225
91
  ref={forwardedRef}
226
92
  id={id}
227
- 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 ?? ""}`}
228
108
  style={style}
229
- $flex={flex}
230
109
  tabIndex={tabIndex}
231
- $active={active}
232
110
  disabled={disabled}
233
- $variant={variant}
234
- $size={size}
235
- $defaultBackground={defaultBackground}
236
111
  onClick={onClick}
237
- // Prevent double clicking a button from triggering any callbacks in ancestors
238
112
  onDoubleClick={useCallback((event: React.MouseEvent) => {
239
113
  event.stopPropagation();
240
114
  }, [])}
241
115
  {...rest}
242
116
  >
243
- <ButtonContent style={contentStyle}>{children}</ButtonContent>
244
- </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>
245
124
  );
246
125
 
247
126
  return tooltip ? (
@@ -250,3 +129,5 @@ export const Button = forwardRef(function Button(
250
129
  buttonElement
251
130
  );
252
131
  });
132
+
133
+ export default Button;