@noya-app/noya-designsystem 0.1.38 → 0.1.40
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 +16 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +416 -321
- package/dist/index.d.ts +416 -321
- package/dist/index.js +9555 -11325
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5057 -6832
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/ActivityIndicator.tsx +13 -4
- package/src/components/AnimatePresence.tsx +261 -0
- package/src/components/Avatar.tsx +202 -80
- package/src/components/Button.tsx +10 -6
- package/src/components/Checkbox.tsx +10 -9
- package/src/components/Chip.tsx +88 -132
- package/src/components/{InputFieldWithCompletions.tsx → Combobox.tsx} +10 -3
- package/src/components/ContextMenu.tsx +9 -5
- package/src/components/Dialog.tsx +20 -23
- package/src/components/Divider.tsx +15 -7
- package/src/components/DraggableMenuButton.tsx +9 -5
- package/src/components/DropdownMenu.tsx +8 -5
- package/src/components/FillInputField.tsx +5 -1
- package/src/components/FillPreviewBackground.tsx +1 -5
- package/src/components/GridView.tsx +71 -46
- package/src/components/InputField.tsx +140 -75
- package/src/components/InspectorPrimitives.tsx +17 -11
- package/src/components/Label.tsx +5 -1
- package/src/components/ListView.tsx +28 -15
- package/src/components/Progress.tsx +10 -7
- package/src/components/SelectMenu.tsx +20 -8
- package/src/components/Slider.tsx +70 -8
- package/src/components/Sortable.tsx +3 -3
- package/src/components/Switch.tsx +19 -2
- package/src/components/Text.tsx +5 -1
- package/src/components/TextArea.tsx +5 -1
- package/src/components/TreeView.tsx +4 -10
- package/src/components/UserPointer.tsx +170 -0
- package/src/components/WorkspaceLayout.tsx +5 -0
- package/src/components/internal/Menu.tsx +14 -5
- package/src/components/internal/TextInput.tsx +13 -0
- package/src/contexts/DialogContext.tsx +30 -18
- package/src/hooks/useTheme.ts +50 -0
- package/src/index.css +16 -13
- package/src/index.tsx +14 -26
- package/src/utils/classNames.ts +5 -0
- package/src/utils/colorFromString.ts +44 -0
- package/tailwind.config.ts +16 -13
- package/src/hooks/useDarkMode.ts +0 -14
- package/src/utils/tailwind.ts +0 -9
|
@@ -5,9 +5,9 @@ import React, {
|
|
|
5
5
|
memo,
|
|
6
6
|
ReactNode,
|
|
7
7
|
} from "react";
|
|
8
|
-
import { cn } from "../utils/tailwind";
|
|
9
8
|
import { Spacer } from "./Spacer";
|
|
10
9
|
import { textStyles } from "./Text";
|
|
10
|
+
import { cx } from "../utils/classNames";
|
|
11
11
|
|
|
12
12
|
export const Section = forwardRef<
|
|
13
13
|
HTMLDivElement,
|
|
@@ -15,7 +15,7 @@ export const Section = forwardRef<
|
|
|
15
15
|
>(({ className, ...props }, ref) => (
|
|
16
16
|
<div
|
|
17
17
|
ref={ref}
|
|
18
|
-
className={
|
|
18
|
+
className={cx(`flex-none flex flex-col `, className)}
|
|
19
19
|
{...props}
|
|
20
20
|
/>
|
|
21
21
|
));
|
|
@@ -24,7 +24,7 @@ export const SectionHeader = forwardRef<
|
|
|
24
24
|
HTMLDivElement,
|
|
25
25
|
React.HTMLAttributes<HTMLDivElement>
|
|
26
26
|
>(({ className, ...props }, ref) => (
|
|
27
|
-
<div ref={ref} className={
|
|
27
|
+
<div ref={ref} className={cx(`flex items-center `, className)} {...props} />
|
|
28
28
|
));
|
|
29
29
|
|
|
30
30
|
type TitleTextStyle = "small" | "heading5" | "heading4" | "heading3";
|
|
@@ -37,7 +37,10 @@ export const Title = forwardRef<
|
|
|
37
37
|
>(({ className, $textStyle, ...props }, ref) => (
|
|
38
38
|
<div
|
|
39
39
|
ref={ref}
|
|
40
|
-
className={
|
|
40
|
+
className={cx(
|
|
41
|
+
`flex select-none ${$textStyle ? `${textStyles[$textStyle]} text-text` : "font-sans text-label uppercase text-text-muted font-bold"} `,
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
41
44
|
{...props}
|
|
42
45
|
/>
|
|
43
46
|
));
|
|
@@ -48,7 +51,7 @@ export const Row = forwardRef<
|
|
|
48
51
|
>(({ className, ...props }, ref) => (
|
|
49
52
|
<div
|
|
50
53
|
ref={ref}
|
|
51
|
-
className={
|
|
54
|
+
className={cx(`flex-1 flex flex-row items-center `, className)}
|
|
52
55
|
{...props}
|
|
53
56
|
/>
|
|
54
57
|
));
|
|
@@ -59,7 +62,7 @@ export const Column = forwardRef<
|
|
|
59
62
|
>(({ className, ...props }, ref) => (
|
|
60
63
|
<div
|
|
61
64
|
ref={ref}
|
|
62
|
-
className={
|
|
65
|
+
className={cx(`flex-1 flex flex-col gap-1 `, className)}
|
|
63
66
|
{...props}
|
|
64
67
|
/>
|
|
65
68
|
));
|
|
@@ -71,7 +74,7 @@ export const Checkbox = forwardRef<
|
|
|
71
74
|
<input
|
|
72
75
|
ref={ref}
|
|
73
76
|
type="checkbox"
|
|
74
|
-
className={
|
|
77
|
+
className={cx(`m-0 focus:z-interactable `, className)}
|
|
75
78
|
{...props}
|
|
76
79
|
/>
|
|
77
80
|
));
|
|
@@ -82,7 +85,7 @@ export const Text = forwardRef<
|
|
|
82
85
|
>(({ className, ...props }, ref) => (
|
|
83
86
|
<span
|
|
84
87
|
ref={ref}
|
|
85
|
-
className={
|
|
88
|
+
className={cx(`font-sans text-heading5 font-normal `, className)}
|
|
86
89
|
{...props}
|
|
87
90
|
/>
|
|
88
91
|
));
|
|
@@ -101,7 +104,7 @@ export const HorizontalSeparator = () => (
|
|
|
101
104
|
// >(({ className, ...props }, ref) => (
|
|
102
105
|
// <span
|
|
103
106
|
// ref={ref}
|
|
104
|
-
// className={`font-sans text-heading5 font-normal text-text-muted -mb-[6px]
|
|
107
|
+
// className={`font-sans text-heading5 font-normal text-text-muted -mb-[6px] `, className}
|
|
105
108
|
// {...props}
|
|
106
109
|
// />
|
|
107
110
|
// ));
|
|
@@ -119,7 +122,10 @@ export const RowLabel = forwardRef(function RowLabel(
|
|
|
119
122
|
return (
|
|
120
123
|
<label
|
|
121
124
|
ref={ref}
|
|
122
|
-
className={
|
|
125
|
+
className={cx(
|
|
126
|
+
`font-sans text-label uppercase flex items-center leading-[19px] font-bold text-text-subtle z-label ${$textStyle && textStyles[$textStyle]} `,
|
|
127
|
+
className
|
|
128
|
+
)}
|
|
123
129
|
{...props}
|
|
124
130
|
/>
|
|
125
131
|
);
|
|
@@ -143,7 +149,7 @@ export const LabeledRow = memo(function LabeledRow({
|
|
|
143
149
|
className,
|
|
144
150
|
}: LabeledRowProps) {
|
|
145
151
|
return (
|
|
146
|
-
<Row id={id} className={className
|
|
152
|
+
<Row id={id} className={className}>
|
|
147
153
|
<Column>
|
|
148
154
|
<RowLabel $textStyle={labelTextStyle}>
|
|
149
155
|
{label}
|
package/src/components/Label.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef, LabelHTMLAttributes, memo } from "react";
|
|
2
|
+
import { cx } from "../utils/classNames";
|
|
2
3
|
|
|
3
4
|
interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {}
|
|
4
5
|
|
|
@@ -10,7 +11,10 @@ export const Label = memo(
|
|
|
10
11
|
return (
|
|
11
12
|
<label
|
|
12
13
|
ref={ref}
|
|
13
|
-
className={
|
|
14
|
+
className={cx(
|
|
15
|
+
`font-sans text-label uppercase flex items-center leading-[19px] select-none font-bold text-text-muted z-label `,
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
14
18
|
{...props}
|
|
15
19
|
/>
|
|
16
20
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Size } from "@noya-app/noya-geometry";
|
|
2
2
|
import { range } from "@noya-app/noya-utils";
|
|
3
|
+
import { forwardRefGeneric, memoGeneric } from "@noya-app/react-utils";
|
|
3
4
|
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
4
5
|
import React, {
|
|
5
6
|
Children,
|
|
@@ -25,6 +26,7 @@ import { ListChildComponentProps, VariableSizeList } from "react-window";
|
|
|
25
26
|
import { mergeEventHandlers } from "../hooks/mergeEventHandlers";
|
|
26
27
|
import { useHover } from "../hooks/useHover";
|
|
27
28
|
import { cssVars } from "../theme";
|
|
29
|
+
import { cx } from "../utils/classNames";
|
|
28
30
|
import { ContextMenu } from "./ContextMenu";
|
|
29
31
|
import { InputField, InputFieldInputProps } from "./InputField";
|
|
30
32
|
import { MenuItem } from "./internal/Menu";
|
|
@@ -105,7 +107,10 @@ const ListViewRowTitle = ({
|
|
|
105
107
|
children: React.ReactNode;
|
|
106
108
|
} & HTMLAttributes<HTMLSpanElement>) => (
|
|
107
109
|
<span
|
|
108
|
-
className={
|
|
110
|
+
className={cx(
|
|
111
|
+
`flex-1 overflow-hidden text-ellipsis whitespace-pre `,
|
|
112
|
+
className
|
|
113
|
+
)}
|
|
109
114
|
{...props}
|
|
110
115
|
>
|
|
111
116
|
{children}
|
|
@@ -123,7 +128,7 @@ const ListViewEditableRowTitleElement = forwardRef(
|
|
|
123
128
|
) => (
|
|
124
129
|
<InputField.Input
|
|
125
130
|
ref={forwardedRef}
|
|
126
|
-
className={`bg-listview-editing-background
|
|
131
|
+
className={cx(`bg-listview-editing-background `, className)}
|
|
127
132
|
{...props}
|
|
128
133
|
/>
|
|
129
134
|
)
|
|
@@ -226,11 +231,14 @@ const RowContainer = forwardRef<
|
|
|
226
231
|
return (
|
|
227
232
|
<div
|
|
228
233
|
ref={ref}
|
|
229
|
-
className={
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
className={cx(
|
|
235
|
+
`${
|
|
236
|
+
$isSectionHeader && $sectionHeaderVariant === "label"
|
|
237
|
+
? "font-sans text-label font-medium"
|
|
238
|
+
: "font-sans text-heading5 font-normal"
|
|
239
|
+
} `,
|
|
240
|
+
className
|
|
241
|
+
)}
|
|
234
242
|
style={{
|
|
235
243
|
...($isSectionHeader && { fontWeight: 500 }),
|
|
236
244
|
gap: $gap,
|
|
@@ -418,7 +426,7 @@ interface ListViewRowProps<MenuItemType extends string = string> {
|
|
|
418
426
|
}) => CSSProperties);
|
|
419
427
|
}
|
|
420
428
|
|
|
421
|
-
const ListViewRow =
|
|
429
|
+
const ListViewRow = forwardRefGeneric(function ListViewRow<
|
|
422
430
|
MenuItemType extends string,
|
|
423
431
|
>(
|
|
424
432
|
{
|
|
@@ -634,7 +642,7 @@ export interface IVirtualizedList {
|
|
|
634
642
|
scrollToIndex(index: number): void;
|
|
635
643
|
}
|
|
636
644
|
|
|
637
|
-
const VirtualizedListInner =
|
|
645
|
+
const VirtualizedListInner = forwardRefGeneric(function VirtualizedListInner<T>(
|
|
638
646
|
{
|
|
639
647
|
size,
|
|
640
648
|
scrollElement,
|
|
@@ -781,7 +789,7 @@ type ListViewRootProps = {
|
|
|
781
789
|
colorScheme?: ListColorScheme;
|
|
782
790
|
};
|
|
783
791
|
|
|
784
|
-
const ListViewRootInner =
|
|
792
|
+
const ListViewRootInner = forwardRefGeneric(function ListViewRootInner<T>(
|
|
785
793
|
{
|
|
786
794
|
id,
|
|
787
795
|
className,
|
|
@@ -1009,7 +1017,10 @@ const ListViewRootInner = forwardRef(function ListViewRootInner<T>(
|
|
|
1009
1017
|
<ListViewDraggingContext.Provider value={draggingContextValue}>
|
|
1010
1018
|
<div
|
|
1011
1019
|
id={id}
|
|
1012
|
-
className={
|
|
1020
|
+
className={cx(
|
|
1021
|
+
`flex flex-col text-text-muted ${scrollable ? "flex-1" : "flex-none"} `,
|
|
1022
|
+
className
|
|
1023
|
+
)}
|
|
1013
1024
|
style={{ ...gapStyle, ...style }}
|
|
1014
1025
|
{...{
|
|
1015
1026
|
[pressEventName]: handleClick,
|
|
@@ -1037,7 +1048,7 @@ const ListViewRootInner = forwardRef(function ListViewRootInner<T>(
|
|
|
1037
1048
|
);
|
|
1038
1049
|
});
|
|
1039
1050
|
|
|
1040
|
-
const ListViewRoot =
|
|
1051
|
+
const ListViewRoot = memoGeneric(ListViewRootInner) as typeof ListViewRootInner;
|
|
1041
1052
|
|
|
1042
1053
|
const ChildrenListViewInner = forwardRef(function ChildrenListViewInner(
|
|
1043
1054
|
{ children, ...rest }: ChildrenProps & ListViewRootProps,
|
|
@@ -1068,7 +1079,9 @@ const ChildrenListViewInner = forwardRef(function ChildrenListViewInner(
|
|
|
1068
1079
|
|
|
1069
1080
|
const ChildrenListView = memo(ChildrenListViewInner);
|
|
1070
1081
|
|
|
1071
|
-
const SimpleListViewInner =
|
|
1082
|
+
const SimpleListViewInner = forwardRefGeneric(function SimpleListViewInner<
|
|
1083
|
+
T = any,
|
|
1084
|
+
>(
|
|
1072
1085
|
props: (ChildrenProps | RenderProps<T>) & ListViewRootProps,
|
|
1073
1086
|
forwardedRef: ForwardedRef<IVirtualizedList>
|
|
1074
1087
|
) {
|
|
@@ -1082,12 +1095,12 @@ const SimpleListViewInner = forwardRef(function SimpleListViewInner<T = any>(
|
|
|
1082
1095
|
/**
|
|
1083
1096
|
* A ListView can be created either with `children` or render props
|
|
1084
1097
|
*/
|
|
1085
|
-
const SimpleListView =
|
|
1098
|
+
const SimpleListView = memoGeneric(SimpleListViewInner);
|
|
1086
1099
|
|
|
1087
1100
|
export namespace ListView {
|
|
1088
1101
|
export const RowTitle = memo(ListViewRowTitle);
|
|
1089
1102
|
export const EditableRowTitle = memo(ListViewEditableRowTitle);
|
|
1090
|
-
export const Row =
|
|
1103
|
+
export const Row = memoGeneric(ListViewRow);
|
|
1091
1104
|
export const Root = SimpleListView;
|
|
1092
1105
|
export const RowContext = ListRowContext;
|
|
1093
1106
|
export type ClickInfo = ListViewClickInfo;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clamp } from "@noya-app/noya-utils";
|
|
2
2
|
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
|
3
3
|
import React, { useMemo } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { cx } from "../utils/classNames";
|
|
5
5
|
|
|
6
6
|
type ProgressVariant = "normal" | "warning" | "primary" | "secondary";
|
|
7
7
|
|
|
@@ -15,20 +15,23 @@ export function Progress({
|
|
|
15
15
|
className?: string;
|
|
16
16
|
}) {
|
|
17
17
|
const clampedValue = clamp(value, 0, 100);
|
|
18
|
-
const transformStyles = useMemo(
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const transformStyles = useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
transform: `translateX(-${100 - clampedValue}%)`,
|
|
21
|
+
}),
|
|
22
|
+
[clampedValue]
|
|
23
|
+
);
|
|
21
24
|
|
|
22
25
|
return (
|
|
23
26
|
<ProgressPrimitive.Root
|
|
24
|
-
className={`relative hidden bg-input-background h-[5px]
|
|
27
|
+
className={cx(`relative hidden bg-input-background h-[5px] `, className)}
|
|
25
28
|
style={{ transform: "translateZ(0)" }}
|
|
26
29
|
value={clampedValue}
|
|
27
30
|
>
|
|
28
31
|
<ProgressPrimitive.Indicator
|
|
29
|
-
|
|
32
|
+
className={`${variant === "primary" ? "bg-primary" : variant === "secondary" ? "bg-secondary" : variant === "warning" ? "bg-warning" : "bg-text"} transition-[transform_660ms_cubic-bezier(0.65,0,0.35,1) w-full h-full`}
|
|
30
33
|
style={transformStyles}
|
|
31
34
|
/>
|
|
32
35
|
</ProgressPrimitive.Root>
|
|
33
36
|
);
|
|
34
|
-
}
|
|
37
|
+
}
|
|
@@ -3,9 +3,11 @@ import {
|
|
|
3
3
|
ChevronUpIcon,
|
|
4
4
|
DropdownChevronIcon,
|
|
5
5
|
} from "@noya-app/noya-icons";
|
|
6
|
+
import { memoGeneric } from "@noya-app/react-utils";
|
|
6
7
|
import * as Select from "@radix-ui/react-select";
|
|
7
8
|
import { type SelectProps } from "@radix-ui/react-select";
|
|
8
|
-
import React, { CSSProperties,
|
|
9
|
+
import React, { CSSProperties, FocusEventHandler, useMemo } from "react";
|
|
10
|
+
import { cx } from "../utils/classNames";
|
|
9
11
|
import { Button } from "./Button";
|
|
10
12
|
import { renderIcon } from "./Icons";
|
|
11
13
|
import { MenuItem, RegularMenuItem, styles } from "./internal/Menu";
|
|
@@ -22,6 +24,8 @@ type Props<T extends string> = {
|
|
|
22
24
|
disabled?: boolean;
|
|
23
25
|
readOnly?: boolean;
|
|
24
26
|
label?: React.ReactNode;
|
|
27
|
+
onFocus?: FocusEventHandler;
|
|
28
|
+
onBlur?: FocusEventHandler;
|
|
25
29
|
} & Pick<SelectProps, "open">;
|
|
26
30
|
|
|
27
31
|
const readOnlyStyle: CSSProperties = {
|
|
@@ -29,7 +33,7 @@ const readOnlyStyle: CSSProperties = {
|
|
|
29
33
|
textAlign: "left",
|
|
30
34
|
};
|
|
31
35
|
|
|
32
|
-
const labelStyles = `font-sans text-label uppercase text-text-disabled leading-[19px] font-bold text-[60%] pointer-events-none flex items-center
|
|
36
|
+
const labelStyles = `font-sans text-label uppercase text-text-disabled leading-[19px] font-bold text-[60%] pointer-events-none flex items-center absolute top-0 bottom-0 right-[1.3rem] z-label`;
|
|
33
37
|
|
|
34
38
|
const scrollButtonStyles = `
|
|
35
39
|
flex
|
|
@@ -41,7 +45,9 @@ const scrollButtonStyles = `
|
|
|
41
45
|
hover:text-text
|
|
42
46
|
`;
|
|
43
47
|
|
|
44
|
-
export const SelectMenu =
|
|
48
|
+
export const SelectMenu = memoGeneric(function SelectMenu<
|
|
49
|
+
T extends string = string,
|
|
50
|
+
>({
|
|
45
51
|
id,
|
|
46
52
|
style,
|
|
47
53
|
className,
|
|
@@ -53,6 +59,8 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
53
59
|
readOnly,
|
|
54
60
|
label,
|
|
55
61
|
open,
|
|
62
|
+
onFocus,
|
|
63
|
+
onBlur,
|
|
56
64
|
}: Props<T>) {
|
|
57
65
|
const selectedItem = menuItems.find(
|
|
58
66
|
(item): item is RegularMenuItem<T> =>
|
|
@@ -66,7 +74,7 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
66
74
|
id={id}
|
|
67
75
|
style={style}
|
|
68
76
|
contentStyle={readOnlyStyle}
|
|
69
|
-
className={`${className
|
|
77
|
+
className={cx(`${className} flex-1 focus:z-interactable`)}
|
|
70
78
|
disabled={disabled}
|
|
71
79
|
>
|
|
72
80
|
{icon && (
|
|
@@ -83,11 +91,11 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
83
91
|
|
|
84
92
|
const trigger = useMemo(
|
|
85
93
|
() => (
|
|
86
|
-
<Select.SelectTrigger asChild>
|
|
94
|
+
<Select.SelectTrigger asChild onFocus={onFocus} onBlur={onBlur}>
|
|
87
95
|
<Button
|
|
88
96
|
id={id}
|
|
89
97
|
style={style}
|
|
90
|
-
className={`${className ?? "w-full"} flex-1 focus:z-interactable`}
|
|
98
|
+
className={`${className ?? "w-full"} flex-1 focus:z-interactable relative`}
|
|
91
99
|
disabled={disabled}
|
|
92
100
|
>
|
|
93
101
|
{icon && (
|
|
@@ -99,12 +107,16 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
99
107
|
<span className="flex flex-1 mr-1.5">
|
|
100
108
|
<Select.Value placeholder={placeholder} />
|
|
101
109
|
</span>
|
|
102
|
-
{label &&
|
|
110
|
+
{label && (
|
|
111
|
+
<label htmlFor={id} className={labelStyles}>
|
|
112
|
+
{label}
|
|
113
|
+
</label>
|
|
114
|
+
)}
|
|
103
115
|
<DropdownChevronIcon />
|
|
104
116
|
</Button>
|
|
105
117
|
</Select.SelectTrigger>
|
|
106
118
|
),
|
|
107
|
-
[id, style, className, disabled, icon, placeholder, label]
|
|
119
|
+
[onFocus, onBlur, id, style, className, disabled, icon, placeholder, label]
|
|
108
120
|
);
|
|
109
121
|
|
|
110
122
|
if (readOnly) {
|
|
@@ -1,31 +1,53 @@
|
|
|
1
|
-
import * as RadixSlider from
|
|
2
|
-
import React, { useCallback, useMemo } from
|
|
1
|
+
import * as RadixSlider from "@radix-ui/react-slider";
|
|
2
|
+
import React, { FocusEventHandler, useCallback, useMemo } from "react";
|
|
3
|
+
import { cx } from "../utils/classNames";
|
|
4
|
+
|
|
5
|
+
type ColorScheme = "primary" | "secondary";
|
|
3
6
|
|
|
4
7
|
interface Props {
|
|
5
8
|
id?: string;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
className?: string;
|
|
6
11
|
value: number;
|
|
7
12
|
onValueChange: (value: number) => void;
|
|
8
13
|
min: number;
|
|
9
14
|
max: number;
|
|
15
|
+
colorScheme?: ColorScheme;
|
|
16
|
+
label?: React.ReactNode;
|
|
17
|
+
onFocus?: FocusEventHandler;
|
|
18
|
+
onBlur?: FocusEventHandler;
|
|
10
19
|
}
|
|
11
20
|
|
|
21
|
+
const labelStyles = `font-sans text-label uppercase text-text-disabled leading-[19px] font-bold text-[60%] pointer-events-none flex items-center z-label`;
|
|
22
|
+
|
|
12
23
|
export const Slider = function Slider({
|
|
13
24
|
id,
|
|
25
|
+
style,
|
|
26
|
+
className,
|
|
14
27
|
value,
|
|
15
28
|
onValueChange,
|
|
16
29
|
min,
|
|
17
30
|
max,
|
|
31
|
+
colorScheme,
|
|
32
|
+
label,
|
|
33
|
+
onFocus,
|
|
34
|
+
onBlur,
|
|
18
35
|
}: Props) {
|
|
19
36
|
const arrayValue = useMemo(
|
|
20
37
|
() => [Math.min(Math.max(value, min), max)],
|
|
21
|
-
[value, min, max]
|
|
38
|
+
[value, min, max]
|
|
22
39
|
);
|
|
23
40
|
|
|
41
|
+
const percentage = useMemo(() => {
|
|
42
|
+
const percent = ((arrayValue[0] - min) / (max - min)) * 100;
|
|
43
|
+
return `${percent}%`;
|
|
44
|
+
}, [arrayValue, min, max]);
|
|
45
|
+
|
|
24
46
|
const handleValueChange = useCallback(
|
|
25
47
|
(arrayValue: number[]) => {
|
|
26
48
|
onValueChange(arrayValue[0]);
|
|
27
49
|
},
|
|
28
|
-
[onValueChange]
|
|
50
|
+
[onValueChange]
|
|
29
51
|
);
|
|
30
52
|
|
|
31
53
|
return (
|
|
@@ -35,12 +57,52 @@ export const Slider = function Slider({
|
|
|
35
57
|
id={id}
|
|
36
58
|
value={arrayValue}
|
|
37
59
|
onValueChange={handleValueChange}
|
|
38
|
-
className=
|
|
60
|
+
className={cx(
|
|
61
|
+
"flex relative items-center select-none touch-none h-[27px]",
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
style={style}
|
|
65
|
+
onFocus={onFocus}
|
|
66
|
+
onBlur={onBlur}
|
|
39
67
|
>
|
|
40
|
-
<RadixSlider.Track className="bg-divider relative flex-grow h-
|
|
41
|
-
|
|
68
|
+
<RadixSlider.Track className="bg-divider relative flex-grow h-full rounded overflow-hidden">
|
|
69
|
+
{label && (
|
|
70
|
+
<label
|
|
71
|
+
htmlFor={id}
|
|
72
|
+
className={cx(labelStyles, "absolute top-0 bottom-0 right-2")}
|
|
73
|
+
>
|
|
74
|
+
{label}
|
|
75
|
+
</label>
|
|
76
|
+
)}
|
|
77
|
+
<RadixSlider.Range
|
|
78
|
+
className={cx(
|
|
79
|
+
"absolute h-full rounded",
|
|
80
|
+
colorScheme === undefined && "bg-slider-border",
|
|
81
|
+
colorScheme === "primary" && "bg-primary",
|
|
82
|
+
colorScheme === "secondary" && "bg-secondary"
|
|
83
|
+
)}
|
|
84
|
+
/>
|
|
42
85
|
</RadixSlider.Track>
|
|
43
|
-
<RadixSlider.Thumb
|
|
86
|
+
<RadixSlider.Thumb
|
|
87
|
+
className={cx(
|
|
88
|
+
"block w-2 h-[27px] rounded border border-solid bg-slider-background focus:outline-none cursor-ew-resize",
|
|
89
|
+
colorScheme === undefined && "border-slider-border",
|
|
90
|
+
colorScheme === "primary" && "border-primary",
|
|
91
|
+
colorScheme === "secondary" && "border-secondary"
|
|
92
|
+
)}
|
|
93
|
+
/>
|
|
94
|
+
{label && (
|
|
95
|
+
<label
|
|
96
|
+
htmlFor={id}
|
|
97
|
+
className={cx(
|
|
98
|
+
labelStyles,
|
|
99
|
+
"absolute top-0 bottom-0 left-2 right-2 text-white overflow-hidden flex justify-end"
|
|
100
|
+
)}
|
|
101
|
+
style={{ clipPath: `inset(0 ${100 - parseFloat(percentage)}% 0 0)` }}
|
|
102
|
+
>
|
|
103
|
+
{label}
|
|
104
|
+
</label>
|
|
105
|
+
)}
|
|
44
106
|
</RadixSlider.Root>
|
|
45
107
|
);
|
|
46
108
|
};
|
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
useSortable,
|
|
16
16
|
verticalListSortingStrategy,
|
|
17
17
|
} from "@dnd-kit/sortable";
|
|
18
|
+
import { memoGeneric } from "@noya-app/react-utils";
|
|
18
19
|
import React, {
|
|
19
20
|
createContext,
|
|
20
|
-
memo,
|
|
21
21
|
ReactNode,
|
|
22
22
|
Ref,
|
|
23
23
|
useCallback,
|
|
@@ -308,6 +308,6 @@ function SortableRoot({
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
export namespace Sortable {
|
|
311
|
-
export const Item =
|
|
312
|
-
export const Root =
|
|
311
|
+
export const Item = memoGeneric(SortableItem);
|
|
312
|
+
export const Root = memoGeneric(SortableRoot);
|
|
313
313
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { CSSProperties, FocusEventHandler } from "react";
|
|
3
|
+
import { cx } from "../utils/classNames";
|
|
3
4
|
|
|
4
5
|
type SwitchColorScheme = "normal" | "primary" | "secondary";
|
|
5
6
|
|
|
@@ -10,6 +11,10 @@ interface Props {
|
|
|
10
11
|
/** @default normal */
|
|
11
12
|
colorScheme?: SwitchColorScheme;
|
|
12
13
|
disabled?: boolean;
|
|
14
|
+
onFocus?: FocusEventHandler;
|
|
15
|
+
onBlur?: FocusEventHandler;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: CSSProperties;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
export const Switch = function Switch({
|
|
@@ -18,16 +23,28 @@ export const Switch = function Switch({
|
|
|
18
23
|
onChange,
|
|
19
24
|
colorScheme = "normal",
|
|
20
25
|
disabled,
|
|
26
|
+
onFocus,
|
|
27
|
+
onBlur,
|
|
28
|
+
style,
|
|
29
|
+
className,
|
|
21
30
|
}: Props) {
|
|
22
31
|
return (
|
|
23
32
|
<SwitchPrimitive.Root
|
|
24
33
|
id={id}
|
|
34
|
+
style={style}
|
|
25
35
|
checked={value}
|
|
26
36
|
disabled={disabled}
|
|
27
37
|
onCheckedChange={(newValue) => {
|
|
28
38
|
onChange(newValue);
|
|
29
39
|
}}
|
|
30
|
-
className={
|
|
40
|
+
className={cx(
|
|
41
|
+
"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",
|
|
42
|
+
colorScheme === "secondary" && "data-[state=checked]:bg-secondary",
|
|
43
|
+
"focus:z-interactable",
|
|
44
|
+
className
|
|
45
|
+
)}
|
|
46
|
+
onFocus={onFocus}
|
|
47
|
+
onBlur={onBlur}
|
|
31
48
|
>
|
|
32
49
|
<SwitchPrimitive.Thumb className="block w-[15px] h-[15px] bg-white rounded-full transition-transform translate-x-[2px] data-[state=checked]:translate-x-[15px]" />
|
|
33
50
|
</SwitchPrimitive.Root>
|
package/src/components/Text.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ForwardedRef, forwardRef, ReactHTML, ReactNode } from "react";
|
|
2
2
|
import { ThemeColor } from "../theme";
|
|
3
3
|
import { camelToKebabCase, KebabToCamelCase } from "../theme/themeUtils";
|
|
4
|
+
import { cx } from "../utils/classNames";
|
|
4
5
|
|
|
5
6
|
type Variant =
|
|
6
7
|
| "title"
|
|
@@ -82,7 +83,10 @@ export const Text = forwardRef(function Text(
|
|
|
82
83
|
<Component
|
|
83
84
|
// @ts-expect-error expected to be many semantic html elements
|
|
84
85
|
ref={forwardedRef}
|
|
85
|
-
className={
|
|
86
|
+
className={cx(
|
|
87
|
+
`${textStyles[variant]} text-${camelToKebabCase(String(color)) ?? "text"} `,
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
86
90
|
style={style}
|
|
87
91
|
tabIndex={tabIndex}
|
|
88
92
|
onClick={onClick}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assignRef } from "@noya-app/react-utils";
|
|
2
2
|
import React, { forwardRef, memo, useCallback, useEffect, useRef } from "react";
|
|
3
|
+
import { cx } from "../utils/classNames";
|
|
3
4
|
|
|
4
5
|
export const useAutoResize = (value: string) => {
|
|
5
6
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
@@ -45,7 +46,10 @@ export const AutoResizingTextArea = memo(
|
|
|
45
46
|
|
|
46
47
|
return (
|
|
47
48
|
<textarea
|
|
48
|
-
className={
|
|
49
|
+
className={cx(
|
|
50
|
+
`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 `,
|
|
51
|
+
className
|
|
52
|
+
)}
|
|
49
53
|
ref={handleRef}
|
|
50
54
|
{...rest}
|
|
51
55
|
onChange={handleChange}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
forwardRef,
|
|
4
|
-
memo,
|
|
5
|
-
ReactNode,
|
|
6
|
-
useCallback,
|
|
7
|
-
useContext,
|
|
8
|
-
} from "react";
|
|
1
|
+
import { forwardRefGeneric, memoGeneric } from "@noya-app/react-utils";
|
|
2
|
+
import React, { ForwardedRef, ReactNode, useCallback, useContext } from "react";
|
|
9
3
|
import { IconButton } from "./IconButton";
|
|
10
4
|
import { IconName, renderIcon } from "./Icons";
|
|
11
5
|
import { ListView } from "./ListView";
|
|
@@ -24,7 +18,7 @@ type TreeRowBaseProps = {
|
|
|
24
18
|
type TreeViewRowProps<MenuItemType extends string> =
|
|
25
19
|
ListView.RowProps<MenuItemType> & TreeRowBaseProps;
|
|
26
20
|
|
|
27
|
-
const TreeRow =
|
|
21
|
+
const TreeRow = forwardRefGeneric(function TreeRow<MenuItemType extends string>(
|
|
28
22
|
{
|
|
29
23
|
icon,
|
|
30
24
|
expanded,
|
|
@@ -79,7 +73,7 @@ export namespace TreeView {
|
|
|
79
73
|
export const Root = ListView.Root;
|
|
80
74
|
export const RowTitle = ListView.RowTitle;
|
|
81
75
|
export const EditableRowTitle = ListView.EditableRowTitle;
|
|
82
|
-
export const Row =
|
|
76
|
+
export const Row = memoGeneric(TreeRow);
|
|
83
77
|
export type ClickInfo = ListView.ClickInfo;
|
|
84
78
|
export type RowProps<MenuItemType extends string> =
|
|
85
79
|
TreeViewRowProps<MenuItemType>;
|