@noya-app/noya-designsystem 0.1.36 → 0.1.38
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 +10 -10
- package/CHANGELOG.md +12 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +358 -33
- package/dist/index.d.ts +358 -33
- package/dist/index.js +1227 -854
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1010 -626
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Button.tsx +1 -1
- package/src/components/Checkbox.tsx +78 -0
- package/src/components/Chip.tsx +15 -8
- package/src/components/DraggableMenuButton.tsx +3 -2
- package/src/components/FillPreviewBackground.tsx +10 -9
- package/src/components/FloatingWindow.tsx +5 -6
- package/src/components/IconButton.tsx +5 -1
- package/src/components/InputField.tsx +95 -68
- package/src/components/InspectorContainer.tsx +2 -2
- package/src/components/InspectorPrimitives.tsx +19 -9
- package/src/components/Label.tsx +16 -29
- package/src/components/ListView.tsx +19 -32
- package/src/components/RadioGroup.tsx +1 -1
- package/src/components/SelectMenu.tsx +41 -35
- package/src/components/Switch.tsx +5 -2
- package/src/components/Text.tsx +20 -7
- package/src/components/TextArea.tsx +1 -1
- package/src/components/Tooltip.tsx +1 -1
- package/src/components/WorkspaceLayout.tsx +4 -3
- package/src/components/internal/TextInput.tsx +1 -0
- package/src/index.css +12 -2
- package/src/index.tsx +1 -1
- package/src/theme/index.ts +6 -3
- package/src/theme/themeUtils.ts +72 -0
- package/src/utils/tailwind.ts +4 -12
- package/src/utils/withSeparatorElements.ts +29 -3
- package/tailwind.config.ts +19 -5
- package/tsconfig.json +1 -1
package/src/components/Label.tsx
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { Spacer } from "./Spacer";
|
|
3
|
-
import { textStyles } from "./Text";
|
|
1
|
+
import React, { forwardRef, LabelHTMLAttributes, memo } from "react";
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
* Root
|
|
7
|
-
* ------------------------------------------------------------------------- */
|
|
3
|
+
interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {}
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
</>
|
|
24
|
-
)}
|
|
25
|
-
</span>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export namespace Label {
|
|
30
|
-
export const Root = memo(LabelRoot);
|
|
31
|
-
}
|
|
5
|
+
export const Label = memo(
|
|
6
|
+
forwardRef<HTMLLabelElement, LabelProps>(function Label(
|
|
7
|
+
{ className, ...props },
|
|
8
|
+
ref
|
|
9
|
+
) {
|
|
10
|
+
return (
|
|
11
|
+
<label
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={`font-sans text-label uppercase flex items-center leading-[19px] select-none font-bold text-text-muted z-label ${className ?? ""}`}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
})
|
|
18
|
+
);
|
|
@@ -24,6 +24,7 @@ import { WindowScroller, WindowScrollerChildProps } from "react-virtualized";
|
|
|
24
24
|
import { ListChildComponentProps, VariableSizeList } from "react-window";
|
|
25
25
|
import { mergeEventHandlers } from "../hooks/mergeEventHandlers";
|
|
26
26
|
import { useHover } from "../hooks/useHover";
|
|
27
|
+
import { cssVars } from "../theme";
|
|
27
28
|
import { ContextMenu } from "./ContextMenu";
|
|
28
29
|
import { InputField, InputFieldInputProps } from "./InputField";
|
|
29
30
|
import { MenuItem } from "./internal/Menu";
|
|
@@ -180,22 +181,6 @@ function getPositionMargin(marginType: ListRowMarginType) {
|
|
|
180
181
|
* Row
|
|
181
182
|
* ------------------------------------------------------------------------- */
|
|
182
183
|
|
|
183
|
-
const theme = {
|
|
184
|
-
colors: {
|
|
185
|
-
textMuted: "var(--text-muted)",
|
|
186
|
-
listView: {
|
|
187
|
-
raisedBackground: "var(--listview-raised-background)",
|
|
188
|
-
},
|
|
189
|
-
secondary: "var(--secondary)",
|
|
190
|
-
primary: "var(--primary)",
|
|
191
|
-
textDisabled: "var(--text-disabled)",
|
|
192
|
-
primaryLight: "var(--primary-light)",
|
|
193
|
-
secondaryLight: "var(--secondary-light)",
|
|
194
|
-
activeBackground: "var(--active-background)",
|
|
195
|
-
dividerSubtle: "var(--divider-subtle)",
|
|
196
|
-
},
|
|
197
|
-
};
|
|
198
|
-
|
|
199
184
|
const RowContainer = forwardRef<
|
|
200
185
|
HTMLDivElement,
|
|
201
186
|
React.HTMLAttributes<HTMLDivElement> & {
|
|
@@ -231,6 +216,7 @@ const RowContainer = forwardRef<
|
|
|
231
216
|
$gap,
|
|
232
217
|
$backgroundColor,
|
|
233
218
|
style,
|
|
219
|
+
"aria-describedby": _, // Causes hydration warning
|
|
234
220
|
...props
|
|
235
221
|
},
|
|
236
222
|
ref
|
|
@@ -264,19 +250,19 @@ const RowContainer = forwardRef<
|
|
|
264
250
|
marginBottom: `${margin.bottom}px`,
|
|
265
251
|
}),
|
|
266
252
|
}),
|
|
267
|
-
color:
|
|
253
|
+
color: cssVars.colors.textMuted,
|
|
268
254
|
...($isSectionHeader && {
|
|
269
|
-
backgroundColor:
|
|
255
|
+
backgroundColor: cssVars.colors.listviewRaisedBackground,
|
|
270
256
|
...($sectionHeaderVariant === "label" && {
|
|
271
|
-
color:
|
|
257
|
+
color: cssVars.colors.textDisabled,
|
|
272
258
|
}),
|
|
273
259
|
}),
|
|
274
260
|
...($disabled && {
|
|
275
|
-
color:
|
|
261
|
+
color: cssVars.colors.textDisabled,
|
|
276
262
|
}),
|
|
277
263
|
...($selected && {
|
|
278
264
|
color: "white",
|
|
279
|
-
backgroundColor:
|
|
265
|
+
backgroundColor: cssVars.colors[$colorScheme],
|
|
280
266
|
}),
|
|
281
267
|
display: "flex",
|
|
282
268
|
alignItems: "center",
|
|
@@ -296,19 +282,19 @@ const RowContainer = forwardRef<
|
|
|
296
282
|
}),
|
|
297
283
|
position: "relative",
|
|
298
284
|
...($hovered && {
|
|
299
|
-
boxShadow: `0 0 0 1px ${
|
|
285
|
+
boxShadow: `0 0 0 1px ${cssVars.colors[$colorScheme]} inset`,
|
|
300
286
|
}),
|
|
301
287
|
...($showsActiveState && {
|
|
302
288
|
"&:active": {
|
|
303
289
|
backgroundColor: $selected
|
|
304
290
|
? $colorScheme === "secondary"
|
|
305
|
-
?
|
|
306
|
-
:
|
|
307
|
-
:
|
|
291
|
+
? cssVars.colors.secondaryLight
|
|
292
|
+
: cssVars.colors.primaryLight
|
|
293
|
+
: cssVars.colors.activeBackground,
|
|
308
294
|
},
|
|
309
295
|
}),
|
|
310
296
|
...($divider && {
|
|
311
|
-
borderBottom: `1px solid ${
|
|
297
|
+
borderBottom: `1px solid ${cssVars.colors.dividerSubtle}`,
|
|
312
298
|
}),
|
|
313
299
|
...($backgroundColor && {
|
|
314
300
|
backgroundColor: $backgroundColor,
|
|
@@ -360,10 +346,10 @@ const ListViewDragIndicatorElement = forwardRef<
|
|
|
360
346
|
...($relativeDropPosition === "inside"
|
|
361
347
|
? {
|
|
362
348
|
inset: 2,
|
|
363
|
-
boxShadow: `0 0 0 1px
|
|
349
|
+
boxShadow: `0 0 0 1px ${cssVars.colors.sidebarBackground}, 0 0 0 3px ${
|
|
364
350
|
$colorScheme === "secondary"
|
|
365
|
-
?
|
|
366
|
-
:
|
|
351
|
+
? cssVars.colors.secondary
|
|
352
|
+
: cssVars.colors.dragOutline
|
|
367
353
|
}`,
|
|
368
354
|
}
|
|
369
355
|
: {
|
|
@@ -380,15 +366,16 @@ const ListViewDragIndicatorElement = forwardRef<
|
|
|
380
366
|
height: 6,
|
|
381
367
|
backgroundColor:
|
|
382
368
|
$colorScheme === "secondary"
|
|
383
|
-
?
|
|
384
|
-
:
|
|
369
|
+
? cssVars.colors.secondary
|
|
370
|
+
: cssVars.colors.primary,
|
|
385
371
|
border: `2px solid white`,
|
|
386
372
|
boxShadow: "0 0 2px rgba(0,0,0,0.5)",
|
|
387
373
|
}),
|
|
388
374
|
...style,
|
|
389
375
|
}}
|
|
390
376
|
/>
|
|
391
|
-
);
|
|
377
|
+
);
|
|
378
|
+
}
|
|
392
379
|
);
|
|
393
380
|
|
|
394
381
|
interface ListViewClickInfo {
|
|
@@ -29,7 +29,7 @@ const ToggleGroupItem = forwardRef(function ToggleGroupItem(
|
|
|
29
29
|
ref={forwardedRef}
|
|
30
30
|
value={value}
|
|
31
31
|
disabled={disabled}
|
|
32
|
-
className={`font-sans text-heading5 font-normal relative flex-1 appearance-none border-none bg-none text-radio-group-item p-0 m-0 rounded inline-flex items-center justify-center align-middle focus:outline-none focus:shadow-[0_0_0_1px_var(--sidebar-background),0_0_0_3px_${colorScheme === "secondary" ? "var(--secondary)" : "var(--primary)"}] aria-checked:bg-${colorScheme ? colorScheme : "radio-group-background"} aria-checked:text-${colorScheme ? "radio-group-background" : "text"} aria-checked:shadow-${colorScheme ? "none" : "0_1px_1px_rgba(0,0,0,0.1)"}`}
|
|
32
|
+
className={`font-sans text-heading5 font-normal relative flex-1 appearance-none border-none bg-none text-radio-group-item p-0 m-0 rounded inline-flex items-center justify-center align-middle focus:outline-none focus:shadow-[0_0_0_1px_var(--sidebar-background),0_0_0_3px_${colorScheme === "secondary" ? "var(--secondary)" : "var(--primary)"}] aria-checked:bg-${colorScheme ? colorScheme : "radio-group-background"} aria-checked:text-${colorScheme ? "radio-group-background" : "text"} aria-checked:shadow-${colorScheme ? "none" : "0_1px_1px_rgba(0,0,0,0.1)"} focus:z-interactable`}
|
|
33
33
|
>
|
|
34
34
|
{children}
|
|
35
35
|
</ToggleGroupPrimitive.Item>
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ChevronDownIcon,
|
|
3
|
+
ChevronUpIcon,
|
|
4
|
+
DropdownChevronIcon,
|
|
5
|
+
} from "@noya-app/noya-icons";
|
|
2
6
|
import * as Select from "@radix-ui/react-select";
|
|
3
7
|
import { type SelectProps } from "@radix-ui/react-select";
|
|
4
8
|
import React, { CSSProperties, memo, useMemo } from "react";
|
|
5
9
|
import { Button } from "./Button";
|
|
6
10
|
import { renderIcon } from "./Icons";
|
|
7
|
-
import { Spacer } from "./Spacer";
|
|
8
11
|
import { MenuItem, RegularMenuItem, styles } from "./internal/Menu";
|
|
12
|
+
import { Spacer } from "./Spacer";
|
|
9
13
|
|
|
10
14
|
type Props<T extends string> = {
|
|
11
15
|
id?: string;
|
|
@@ -25,11 +29,17 @@ const readOnlyStyle: CSSProperties = {
|
|
|
25
29
|
textAlign: "left",
|
|
26
30
|
};
|
|
27
31
|
|
|
28
|
-
const
|
|
29
|
-
fontSize: "0.85rem",
|
|
30
|
-
};
|
|
32
|
+
const labelStyles = `font-sans text-label uppercase text-text-disabled leading-[19px] font-bold text-[60%] pointer-events-none flex items-center mr-1.5 z-label`;
|
|
31
33
|
|
|
32
|
-
const
|
|
34
|
+
const scrollButtonStyles = `
|
|
35
|
+
flex
|
|
36
|
+
items-center
|
|
37
|
+
justify-center
|
|
38
|
+
h-[25px]
|
|
39
|
+
cursor-default
|
|
40
|
+
text-text-muted
|
|
41
|
+
hover:text-text
|
|
42
|
+
`;
|
|
33
43
|
|
|
34
44
|
export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
35
45
|
id,
|
|
@@ -56,7 +66,7 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
56
66
|
id={id}
|
|
57
67
|
style={style}
|
|
58
68
|
contentStyle={readOnlyStyle}
|
|
59
|
-
className={`${className ?? ""} flex-1`}
|
|
69
|
+
className={`${className ?? ""} flex-1 focus:z-interactable`}
|
|
60
70
|
disabled={disabled}
|
|
61
71
|
>
|
|
62
72
|
{icon && (
|
|
@@ -65,9 +75,7 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
65
75
|
<Spacer.Horizontal inline size={6} />
|
|
66
76
|
</>
|
|
67
77
|
)}
|
|
68
|
-
<span
|
|
69
|
-
{selectedItem?.title ?? value}
|
|
70
|
-
</span>
|
|
78
|
+
<span className="flex flex-1">{selectedItem?.title ?? value}</span>
|
|
71
79
|
</Button>
|
|
72
80
|
),
|
|
73
81
|
[icon, id, style, className, disabled, value, selectedItem]
|
|
@@ -78,8 +86,8 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
78
86
|
<Select.SelectTrigger asChild>
|
|
79
87
|
<Button
|
|
80
88
|
id={id}
|
|
81
|
-
style={
|
|
82
|
-
className={`${className ?? "w-full"} flex-1`}
|
|
89
|
+
style={style}
|
|
90
|
+
className={`${className ?? "w-full"} flex-1 focus:z-interactable`}
|
|
83
91
|
disabled={disabled}
|
|
84
92
|
>
|
|
85
93
|
{icon && (
|
|
@@ -88,25 +96,22 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
88
96
|
<Spacer.Horizontal inline size={6} />
|
|
89
97
|
</>
|
|
90
98
|
)}
|
|
91
|
-
<span className="flex flex-1">
|
|
99
|
+
<span className="flex flex-1 mr-1.5">
|
|
92
100
|
<Select.Value placeholder={placeholder} />
|
|
93
101
|
</span>
|
|
94
|
-
<
|
|
102
|
+
{label && <span className={labelStyles}>{label}</span>}
|
|
95
103
|
<DropdownChevronIcon />
|
|
96
104
|
</Button>
|
|
97
105
|
</Select.SelectTrigger>
|
|
98
106
|
),
|
|
99
|
-
[
|
|
107
|
+
[id, style, className, disabled, icon, placeholder, label]
|
|
100
108
|
);
|
|
101
109
|
|
|
102
110
|
if (readOnly) {
|
|
103
111
|
return label ? (
|
|
104
112
|
<div className="flex flex-col relative">
|
|
105
113
|
{readOnlyButton}
|
|
106
|
-
<label
|
|
107
|
-
className={labelStyles}
|
|
108
|
-
htmlFor={id}
|
|
109
|
-
>
|
|
114
|
+
<label className={labelStyles} htmlFor={id}>
|
|
110
115
|
{label}
|
|
111
116
|
</label>
|
|
112
117
|
</div>
|
|
@@ -117,20 +122,12 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
117
122
|
|
|
118
123
|
return (
|
|
119
124
|
<Select.Root value={value} onValueChange={onSelect} open={open}>
|
|
120
|
-
{
|
|
121
|
-
<div className="flex-1 flex-col relative">
|
|
122
|
-
{trigger}
|
|
123
|
-
{label && (
|
|
124
|
-
<label className={labelStyles} htmlFor={id}>
|
|
125
|
-
{label}
|
|
126
|
-
</label>
|
|
127
|
-
)}
|
|
128
|
-
</div>
|
|
129
|
-
) : (
|
|
130
|
-
trigger
|
|
131
|
-
)}
|
|
125
|
+
{trigger}
|
|
132
126
|
<Select.Portal>
|
|
133
127
|
<Select.Content className={styles.contentStyle}>
|
|
128
|
+
<Select.ScrollUpButton className={scrollButtonStyles}>
|
|
129
|
+
<ChevronUpIcon />
|
|
130
|
+
</Select.ScrollUpButton>
|
|
134
131
|
<Select.Viewport>
|
|
135
132
|
{menuItems.map((menuItem) => {
|
|
136
133
|
if (typeof menuItem === "string") {
|
|
@@ -146,6 +143,9 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
146
143
|
);
|
|
147
144
|
})}
|
|
148
145
|
</Select.Viewport>
|
|
146
|
+
<Select.ScrollDownButton className={scrollButtonStyles}>
|
|
147
|
+
<ChevronDownIcon />
|
|
148
|
+
</Select.ScrollDownButton>
|
|
149
149
|
</Select.Content>
|
|
150
150
|
</Select.Portal>
|
|
151
151
|
</Select.Root>
|
|
@@ -156,21 +156,27 @@ const SelectItem = React.forwardRef(
|
|
|
156
156
|
(
|
|
157
157
|
{
|
|
158
158
|
children,
|
|
159
|
-
icon,
|
|
159
|
+
icon,
|
|
160
|
+
disabled,
|
|
160
161
|
...props
|
|
161
162
|
}: Select.SelectItemProps & { icon?: React.ReactNode },
|
|
162
163
|
forwardedRef: React.ForwardedRef<HTMLDivElement>
|
|
163
164
|
) => {
|
|
164
165
|
return (
|
|
165
|
-
<Select.Item
|
|
166
|
+
<Select.Item
|
|
167
|
+
className={styles.itemStyle({ disabled })}
|
|
168
|
+
disabled={disabled}
|
|
169
|
+
{...props}
|
|
170
|
+
ref={forwardedRef}
|
|
171
|
+
>
|
|
166
172
|
{icon && (
|
|
167
173
|
<>
|
|
168
174
|
{renderIcon(icon)}
|
|
169
175
|
<Spacer.Horizontal size={8} />
|
|
170
176
|
</>
|
|
171
177
|
)}
|
|
172
|
-
<Select.ItemText
|
|
178
|
+
<Select.ItemText>{children}</Select.ItemText>
|
|
173
179
|
</Select.Item>
|
|
174
180
|
);
|
|
175
181
|
}
|
|
176
|
-
);
|
|
182
|
+
);
|
|
@@ -4,6 +4,7 @@ import React from "react";
|
|
|
4
4
|
type SwitchColorScheme = "normal" | "primary" | "secondary";
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
+
id?: string;
|
|
7
8
|
value: boolean;
|
|
8
9
|
onChange: (value: boolean) => void;
|
|
9
10
|
/** @default normal */
|
|
@@ -12,6 +13,7 @@ interface Props {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const Switch = function Switch({
|
|
16
|
+
id,
|
|
15
17
|
value,
|
|
16
18
|
onChange,
|
|
17
19
|
colorScheme = "normal",
|
|
@@ -19,14 +21,15 @@ export const Switch = function Switch({
|
|
|
19
21
|
}: Props) {
|
|
20
22
|
return (
|
|
21
23
|
<SwitchPrimitive.Root
|
|
24
|
+
id={id}
|
|
22
25
|
checked={value}
|
|
23
26
|
disabled={disabled}
|
|
24
27
|
onCheckedChange={(newValue) => {
|
|
25
28
|
onChange(newValue);
|
|
26
29
|
}}
|
|
27
|
-
className={`all-unset w-8 h-[19px] bg-active-background rounded-full relative cursor-pointer [webkit-tap-highlight-color:rgba(0,0,0,0)] focus:ring-2 focus:
|
|
30
|
+
className={`all-unset w-8 h-[19px] bg-active-background rounded-full relative cursor-pointer [webkit-tap-highlight-color:rgba(0,0,0,0)] focus:ring-2 focus:ring-primary focus:ring-offset-[1px] outline-none data-[state=checked]:bg-primary ${colorScheme === "secondary" && "data-[state=checked]:bg-secondary"} focus:z-interactable`}
|
|
28
31
|
>
|
|
29
|
-
<SwitchPrimitive.Thumb className="block w-[15px] h-[15px] bg-white rounded-full transition-transform translate-x-[2px] data-[state=checked]:translate-x-[15px]"/>
|
|
32
|
+
<SwitchPrimitive.Thumb className="block w-[15px] h-[15px] bg-white rounded-full transition-transform translate-x-[2px] data-[state=checked]:translate-x-[15px]" />
|
|
30
33
|
</SwitchPrimitive.Root>
|
|
31
34
|
);
|
|
32
35
|
};
|
package/src/components/Text.tsx
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import React, { ForwardedRef, forwardRef, ReactHTML, ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { ThemeColor } from "../theme";
|
|
3
|
+
import { camelToKebabCase, KebabToCamelCase } from "../theme/themeUtils";
|
|
4
|
+
|
|
5
|
+
type Variant =
|
|
6
|
+
| "title"
|
|
7
|
+
| "subtitle"
|
|
8
|
+
| "heading1"
|
|
9
|
+
| "heading2"
|
|
10
|
+
| "heading3"
|
|
11
|
+
| "heading4"
|
|
12
|
+
| "heading5"
|
|
13
|
+
| "body"
|
|
14
|
+
| "small"
|
|
15
|
+
| "button"
|
|
16
|
+
| "code"
|
|
17
|
+
| "label";
|
|
5
18
|
|
|
6
19
|
const elements: Record<Variant, keyof ReactHTML> = {
|
|
7
20
|
title: "h1",
|
|
@@ -33,19 +46,19 @@ export const textStyles: Record<Variant, string> = {
|
|
|
33
46
|
label: "font-sans text-label font-normal uppercase",
|
|
34
47
|
} as const;
|
|
35
48
|
|
|
36
|
-
export type
|
|
49
|
+
export type TextProps = {
|
|
37
50
|
as?: keyof ReactHTML;
|
|
38
51
|
href?: string;
|
|
39
52
|
className?: string;
|
|
40
53
|
style?: React.CSSProperties;
|
|
41
54
|
variant: Variant;
|
|
42
|
-
color?: ThemeColor
|
|
55
|
+
color?: KebabToCamelCase<ThemeColor>;
|
|
43
56
|
children: ReactNode;
|
|
44
57
|
onClick?: () => void;
|
|
45
58
|
onDoubleClick?: () => void;
|
|
46
59
|
onKeyDown?: (event: React.KeyboardEvent<HTMLSpanElement>) => void;
|
|
47
60
|
tabIndex?: number;
|
|
48
|
-
}
|
|
61
|
+
};
|
|
49
62
|
|
|
50
63
|
export const Text = forwardRef(function Text(
|
|
51
64
|
{
|
|
@@ -69,7 +82,7 @@ export const Text = forwardRef(function Text(
|
|
|
69
82
|
<Component
|
|
70
83
|
// @ts-expect-error expected to be many semantic html elements
|
|
71
84
|
ref={forwardedRef}
|
|
72
|
-
className={`${textStyles[variant]} text-${
|
|
85
|
+
className={`${textStyles[variant]} text-${camelToKebabCase(String(color)) ?? "text"} ${className ?? ""}`}
|
|
73
86
|
style={style}
|
|
74
87
|
tabIndex={tabIndex}
|
|
75
88
|
onClick={onClick}
|
|
@@ -45,7 +45,7 @@ export const AutoResizingTextArea = memo(
|
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
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
|
|
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 read-only:text-text-disabled focus:z-interactable ${className ?? ""}`}
|
|
49
49
|
ref={handleRef}
|
|
50
50
|
{...rest}
|
|
51
51
|
onChange={handleChange}
|
|
@@ -22,7 +22,7 @@ export const Tooltip = memo(function Tooltip({ children, content }: Props) {
|
|
|
22
22
|
align="center"
|
|
23
23
|
sideOffset={2}
|
|
24
24
|
collisionPadding={8}
|
|
25
|
-
className={`${textStyles.small} text-text rounded-[3px] py-small px-medium bg-popover-background shadow-[
|
|
25
|
+
className={`${textStyles.small} text-text rounded-[3px] py-small px-medium bg-popover-background shadow-[0_2px_4px_rgba(0,0,0,0.2)_0_0_12px_rgba(0,0,0,0.1)] border border-solid border-divider-strong`}
|
|
26
26
|
>
|
|
27
27
|
{content}
|
|
28
28
|
{/* <Arrow /> */}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
usePreservePanelSize,
|
|
23
23
|
} from "../hooks/usePreservePanelSize";
|
|
24
24
|
import { useWindowSize } from "../hooks/useWindowSize";
|
|
25
|
+
import { cssVars } from "../theme";
|
|
25
26
|
|
|
26
27
|
interface Props {
|
|
27
28
|
autoSavePrefix?: string;
|
|
@@ -184,7 +185,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
184
185
|
id={id}
|
|
185
186
|
className={className}
|
|
186
187
|
style={{
|
|
187
|
-
backgroundColor:
|
|
188
|
+
backgroundColor: cssVars.colors.canvasBackground,
|
|
188
189
|
display: "flex",
|
|
189
190
|
flexDirection: "row",
|
|
190
191
|
...style,
|
|
@@ -226,7 +227,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
226
227
|
cursor: "col-resize",
|
|
227
228
|
width: "1px",
|
|
228
229
|
height: "100%",
|
|
229
|
-
backgroundColor:
|
|
230
|
+
backgroundColor: cssVars.colors.divider,
|
|
230
231
|
}}
|
|
231
232
|
/>
|
|
232
233
|
</>
|
|
@@ -251,7 +252,7 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
251
252
|
cursor: "col-resize",
|
|
252
253
|
width: "1px",
|
|
253
254
|
height: "100%",
|
|
254
|
-
backgroundColor:
|
|
255
|
+
backgroundColor: cssVars.colors.divider,
|
|
255
256
|
}}
|
|
256
257
|
/>
|
|
257
258
|
<Panel
|
package/src/index.css
CHANGED
|
@@ -65,7 +65,17 @@
|
|
|
65
65
|
--radio-group-item: rgb(139, 139, 139);
|
|
66
66
|
--dot: rgba(0,0,0,0.25);
|
|
67
67
|
--row-highlight: #3390FF10;
|
|
68
|
-
--table-row-background: var(--background)
|
|
68
|
+
--table-row-background: var(--background);
|
|
69
|
+
--interactable-z-index: 2;
|
|
70
|
+
--label-z-index: 3;
|
|
71
|
+
--chip-primary-bg: rgba(238,229,255,0.2);
|
|
72
|
+
--chip-secondary-bg: rgba(205,238,231,0.2);
|
|
73
|
+
--chip-error-bg: rgba(255,219,219,0.2);
|
|
74
|
+
--chip-default-bg: rgba(0,0,0,0.1);
|
|
75
|
+
--chip-primary-shadow: rgb(238,229,255);
|
|
76
|
+
--chip-secondary-shadow: rgb(205,238,231);
|
|
77
|
+
--chip-error-shadow: rgb(255,219,219);
|
|
78
|
+
--chip-default-shadow: rgb(0,0,0);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
[data-theme="dark"] {
|
|
@@ -105,4 +115,4 @@
|
|
|
105
115
|
--thumbnail-shadow: #1f1d3366;
|
|
106
116
|
--dot: rgba(255,255,255,0.15);
|
|
107
117
|
--table-row-background: var(--sidebar-background);
|
|
108
|
-
}
|
|
118
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -17,6 +17,7 @@ declare module "react" {
|
|
|
17
17
|
export * from "./components/ActivityIndicator";
|
|
18
18
|
export * from "./components/Avatar";
|
|
19
19
|
export * from "./components/Button";
|
|
20
|
+
export * from "./components/Checkbox";
|
|
20
21
|
export * from "./components/Chip";
|
|
21
22
|
export * from "./components/ContextMenu";
|
|
22
23
|
export * from "./components/Dialog";
|
|
@@ -70,7 +71,6 @@ export * from "./hooks/usePlatform";
|
|
|
70
71
|
export * from "./mediaQuery";
|
|
71
72
|
export * from "./theme";
|
|
72
73
|
export { cn } from './utils/tailwind';
|
|
73
|
-
export type { ThemeColor } from './utils/tailwind';
|
|
74
74
|
export * from "./utils/createSectionedMenu";
|
|
75
75
|
export * from "./utils/getGradientBackground";
|
|
76
76
|
export * from "./hooks/usePreservePanelSize";
|
package/src/theme/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import tailwindConfig from "../../tailwind.config";
|
|
2
|
+
import { convertKebabToCamelCase } from "./themeUtils";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export type
|
|
4
|
+
export type Theme = (typeof tailwindConfig.theme)["extend"];
|
|
5
|
+
|
|
6
|
+
export type ThemeColor = keyof Theme["colors"];
|
|
7
|
+
|
|
8
|
+
export const cssVars = convertKebabToCamelCase(tailwindConfig.theme.extend);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type KebabToCamelCase<S extends string> =
|
|
2
|
+
S extends `${infer First}-${infer Rest}`
|
|
3
|
+
? `${First}${Capitalize<KebabToCamelCase<Rest>>}`
|
|
4
|
+
: S;
|
|
5
|
+
|
|
6
|
+
type IsPlainObject<T> = T extends Array<any> | Set<any> | Map<any, any>
|
|
7
|
+
? false
|
|
8
|
+
: T extends object
|
|
9
|
+
? true
|
|
10
|
+
: false;
|
|
11
|
+
|
|
12
|
+
type KebabToCamelCaseKeys<T> = {
|
|
13
|
+
[K in keyof T as K extends string
|
|
14
|
+
? KebabToCamelCase<K>
|
|
15
|
+
: K]: T[K] extends object
|
|
16
|
+
? IsPlainObject<T[K]> extends true
|
|
17
|
+
? KebabToCamelCaseKeys<T[K]>
|
|
18
|
+
: T[K]
|
|
19
|
+
: T[K];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type _CamelToKebabCase<S extends string> = S extends `${infer C}${infer Rest}`
|
|
23
|
+
? C extends Uppercase<C>
|
|
24
|
+
? `-${Lowercase<C>}${_CamelToKebabCase<Rest>}`
|
|
25
|
+
: `${C}${_CamelToKebabCase<Rest>}`
|
|
26
|
+
: S;
|
|
27
|
+
|
|
28
|
+
// Remove leading hyphen if exists
|
|
29
|
+
type TrimHyphen<S extends string> = S extends `-${infer Rest}` ? Rest : S;
|
|
30
|
+
|
|
31
|
+
export type CamelToKebabCase<S extends string> = TrimHyphen<
|
|
32
|
+
_CamelToKebabCase<S>
|
|
33
|
+
>;
|
|
34
|
+
|
|
35
|
+
export function camelToKebabCase<S extends string>(
|
|
36
|
+
str: S
|
|
37
|
+
): CamelToKebabCase<S> {
|
|
38
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase() as CamelToKebabCase<S>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function kebabToCamelCase<S extends string>(
|
|
42
|
+
str: S
|
|
43
|
+
): KebabToCamelCase<S> {
|
|
44
|
+
return str.replace(/-([a-z])/g, (_, letter) =>
|
|
45
|
+
letter.toUpperCase()
|
|
46
|
+
) as KebabToCamelCase<S>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Runtime function to convert all keys in an object from kebab-case to camelCase
|
|
50
|
+
export function convertKebabToCamelCase<T extends object>(
|
|
51
|
+
obj: T
|
|
52
|
+
): KebabToCamelCaseKeys<T> {
|
|
53
|
+
if (Array.isArray(obj) || obj instanceof Set || obj instanceof Map) {
|
|
54
|
+
return obj as KebabToCamelCaseKeys<T>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const result: any = {};
|
|
58
|
+
|
|
59
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
60
|
+
const camelKey = kebabToCamelCase(key);
|
|
61
|
+
result[camelKey] =
|
|
62
|
+
value &&
|
|
63
|
+
typeof value === "object" &&
|
|
64
|
+
!Array.isArray(value) &&
|
|
65
|
+
!(value instanceof Set) &&
|
|
66
|
+
!(value instanceof Map)
|
|
67
|
+
? convertKebabToCamelCase(value)
|
|
68
|
+
: value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result as KebabToCamelCaseKeys<T>;
|
|
72
|
+
}
|
package/src/utils/tailwind.ts
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import { Theme } from '../theme';
|
|
2
1
|
import { twMerge } from "tailwind-merge";
|
|
3
2
|
|
|
4
|
-
/**
|
|
3
|
+
/**
|
|
5
4
|
* Utility for merging classes conditionally. Right side will override left side if there are any conflicts.
|
|
6
5
|
* Usage: cn('bg-red-500 text-white', 'bg-blue-500') // Returns: 'text-white bg-blue-500'
|
|
7
6
|
* @danger do not use this function to concatenate class names. Use it to merge classes conditionally.
|
|
8
|
-
*/
|
|
9
|
-
export const cn = (...classes: (string | boolean | undefined | null)[]) =>
|
|
10
|
-
|
|
11
|
-
// @ts-expect-error TODO: figure this out
|
|
12
|
-
type ThemeExtend = NonNullable<Theme['extend']>
|
|
13
|
-
export type ThemeColor = keyof ThemeExtend['colors'];
|
|
14
|
-
|
|
15
|
-
export function camelCaseToKebabCase(string: string) {
|
|
16
|
-
return string.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
17
|
-
}
|
|
7
|
+
*/
|
|
8
|
+
export const cn = (...classes: (string | boolean | undefined | null)[]) =>
|
|
9
|
+
twMerge(classes.filter(Boolean) as string[]);
|