@noya-app/noya-designsystem 0.1.36 → 0.1.37
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 +8 -8
- package/CHANGELOG.md +6 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +15 -10
- package/dist/index.d.ts +15 -10
- package/dist/index.js +843 -738
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +620 -507
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Checkbox.tsx +76 -0
- package/src/components/Label.tsx +16 -29
- package/src/components/SelectMenu.tsx +39 -33
- package/src/components/Switch.tsx +5 -2
- package/src/index.tsx +1 -0
- package/src/utils/withSeparatorElements.ts +29 -3
- package/tailwind.config.ts +3 -2
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React, { forwardRef, InputHTMLAttributes, memo } from "react";
|
|
2
|
+
|
|
3
|
+
interface CheckboxProps
|
|
4
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
5
|
+
colorScheme?: "primary" | "secondary";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const colorSchemeStyles = {
|
|
9
|
+
normal: "text-text-subtle",
|
|
10
|
+
primary: "text-primary",
|
|
11
|
+
secondary: "text-secondary",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const Checkbox = memo(
|
|
15
|
+
forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox(
|
|
16
|
+
{ className, colorScheme = "secondary", ...props },
|
|
17
|
+
ref
|
|
18
|
+
) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
className={`relative inline-flex w-[19px] h-[19px] ${colorSchemeStyles[colorScheme]} ${className ?? ""}`}
|
|
22
|
+
>
|
|
23
|
+
<input
|
|
24
|
+
ref={ref}
|
|
25
|
+
type="checkbox"
|
|
26
|
+
className={`
|
|
27
|
+
w-full
|
|
28
|
+
h-full
|
|
29
|
+
peer
|
|
30
|
+
appearance-none
|
|
31
|
+
rounded
|
|
32
|
+
bg-input-background
|
|
33
|
+
transition-colors
|
|
34
|
+
border
|
|
35
|
+
border-input-border
|
|
36
|
+
disabled:opacity-50
|
|
37
|
+
disabled:cursor-not-allowed
|
|
38
|
+
focus:ring-2
|
|
39
|
+
focus:ring-primary
|
|
40
|
+
focus:ring-offset-1
|
|
41
|
+
`}
|
|
42
|
+
style={{
|
|
43
|
+
width: "27px",
|
|
44
|
+
...props.style,
|
|
45
|
+
}}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
<svg
|
|
49
|
+
className={`
|
|
50
|
+
absolute
|
|
51
|
+
inset-0
|
|
52
|
+
h-[27px]
|
|
53
|
+
w-[27px]
|
|
54
|
+
pointer-events-none
|
|
55
|
+
stroke-white
|
|
56
|
+
opacity-0
|
|
57
|
+
peer-checked:opacity-100
|
|
58
|
+
`}
|
|
59
|
+
style={{
|
|
60
|
+
strokeWidth: "1.3",
|
|
61
|
+
}}
|
|
62
|
+
viewBox="0 0 16 16"
|
|
63
|
+
fill="none"
|
|
64
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
65
|
+
>
|
|
66
|
+
<path
|
|
67
|
+
d="M3 6L4.5 7.5L8 4"
|
|
68
|
+
strokeLinecap="round"
|
|
69
|
+
strokeLinejoin="round"
|
|
70
|
+
stroke="currentColor"
|
|
71
|
+
/>
|
|
72
|
+
</svg>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
})
|
|
76
|
+
);
|
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 ${className ?? ""}`}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
})
|
|
18
|
+
);
|
|
@@ -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`;
|
|
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,
|
|
@@ -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,7 +86,7 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
78
86
|
<Select.SelectTrigger asChild>
|
|
79
87
|
<Button
|
|
80
88
|
id={id}
|
|
81
|
-
style={
|
|
89
|
+
style={style}
|
|
82
90
|
className={`${className ?? "w-full"} flex-1`}
|
|
83
91
|
disabled={disabled}
|
|
84
92
|
>
|
|
@@ -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"}`}
|
|
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/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";
|
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
Fragment,
|
|
5
|
+
isValidElement,
|
|
6
|
+
ReactNode,
|
|
7
|
+
} from "react";
|
|
8
|
+
|
|
9
|
+
interface SeparatorOptions {
|
|
10
|
+
traverseFragments?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function flattenChildren(
|
|
14
|
+
children: ReactNode,
|
|
15
|
+
traverseFragments: boolean
|
|
16
|
+
): ReactNode[] {
|
|
17
|
+
return Children.toArray(children).flatMap((child) => {
|
|
18
|
+
if (traverseFragments && isValidElement(child) && child.type === Fragment) {
|
|
19
|
+
return flattenChildren(child.props.children, traverseFragments);
|
|
20
|
+
}
|
|
21
|
+
return child;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
2
24
|
|
|
3
25
|
function createKey(key: string | number) {
|
|
4
26
|
return `s-${key}`;
|
|
@@ -6,9 +28,13 @@ function createKey(key: string | number) {
|
|
|
6
28
|
|
|
7
29
|
export default function withSeparatorElements(
|
|
8
30
|
elements: ReactNode,
|
|
9
|
-
separator: ReactNode | (() => ReactNode)
|
|
31
|
+
separator: ReactNode | (() => ReactNode),
|
|
32
|
+
options?: SeparatorOptions
|
|
10
33
|
) {
|
|
11
|
-
const childrenArray =
|
|
34
|
+
const childrenArray = flattenChildren(
|
|
35
|
+
elements,
|
|
36
|
+
options?.traverseFragments ?? true
|
|
37
|
+
);
|
|
12
38
|
|
|
13
39
|
for (let i = childrenArray.length - 1; i > 0; i--) {
|
|
14
40
|
let sep =
|
package/tailwind.config.ts
CHANGED