@noya-app/noya-designsystem 0.1.30 → 0.1.31
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 +9 -9
- package/.turbo/turbo-lint.log +13 -0
- package/CHANGELOG.md +10 -0
- package/dist/index.d.mts +167 -179
- package/dist/index.d.ts +167 -179
- package/dist/index.js +253 -307
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +244 -303
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
- package/src/components/Button.tsx +5 -3
- package/src/components/InputField.tsx +115 -88
- package/src/components/SelectMenu.tsx +69 -12
- package/src/components/Stack.tsx +10 -1
- package/src/components/WorkspaceLayout.tsx +24 -4
- package/src/index.tsx +1 -1
- package/tailwind.config.ts +283 -0
- package/tailwind.d.ts +11 -0
- package/tsconfig.json +4 -1
- package/src/components/Select.tsx +0 -183
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noya-app/noya-designsystem",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@dnd-kit/sortable": "4.0.0",
|
|
16
16
|
"@noya-app/noya-colorpicker": "0.1.11",
|
|
17
17
|
"@noya-app/noya-utils": "0.1.2",
|
|
18
|
-
"@noya-app/noya-geometry": "0.1.
|
|
18
|
+
"@noya-app/noya-geometry": "0.1.5",
|
|
19
19
|
"@noya-app/noya-icons": "0.1.4",
|
|
20
20
|
"@noya-app/noya-keymap": "0.1.2",
|
|
21
21
|
"@radix-ui/primitive": "^1.0.0",
|
|
@@ -46,8 +46,9 @@
|
|
|
46
46
|
"@types/react-dom": "*",
|
|
47
47
|
"@types/react-virtualized": "^9.21.21",
|
|
48
48
|
"@types/react-window": "^1.8.5",
|
|
49
|
+
"esbuild-plugin-react-virtualized": "1.0.4",
|
|
49
50
|
"react-virtualized": "9.22.5",
|
|
50
|
-
"
|
|
51
|
+
"tailwindcss": "^3.4.14"
|
|
51
52
|
},
|
|
52
53
|
"peerDependencies": {
|
|
53
54
|
"react": "*",
|
|
@@ -19,7 +19,7 @@ type ButtonVariant =
|
|
|
19
19
|
| "floating"
|
|
20
20
|
| "none";
|
|
21
21
|
|
|
22
|
-
type ButtonSize = "normal" | "large";
|
|
22
|
+
type ButtonSize = "small" | "normal" | "large";
|
|
23
23
|
|
|
24
24
|
/* ----------------------------------------------------------------------------
|
|
25
25
|
* Element
|
|
@@ -135,8 +135,8 @@ export const ButtonElement = styled.button<{
|
|
|
135
135
|
background: "white",
|
|
136
136
|
color: theme.colors.text,
|
|
137
137
|
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.1)",
|
|
138
|
-
fontSize: "12px",
|
|
139
|
-
padding: "0px 4px",
|
|
138
|
+
fontSize: $size === "small" ? "10px" : "12px",
|
|
139
|
+
padding: $size === "small" ? "0px 2px" : "0px 4px",
|
|
140
140
|
"&:hover": {
|
|
141
141
|
opacity: 0.8,
|
|
142
142
|
},
|
|
@@ -184,7 +184,9 @@ export interface ButtonRootProps {
|
|
|
184
184
|
children: ReactNode;
|
|
185
185
|
active?: boolean;
|
|
186
186
|
disabled?: boolean;
|
|
187
|
+
/** @default normal */
|
|
187
188
|
variant?: ButtonVariant;
|
|
189
|
+
/** @default normal */
|
|
188
190
|
size?: ButtonSize;
|
|
189
191
|
tooltip?: ReactNode;
|
|
190
192
|
onClick?: (event: React.MouseEvent) => void;
|
|
@@ -32,8 +32,8 @@ export type InputFieldSize = "small" | "medium" | "large";
|
|
|
32
32
|
|
|
33
33
|
type InputFieldContextValue = {
|
|
34
34
|
labelPosition: LabelPosition;
|
|
35
|
-
labelSize
|
|
36
|
-
|
|
35
|
+
labelSize?: number;
|
|
36
|
+
buttonSize?: number;
|
|
37
37
|
hasDropdown: boolean;
|
|
38
38
|
/** @default medium */
|
|
39
39
|
size: InputFieldSize;
|
|
@@ -42,12 +42,13 @@ type InputFieldContextValue = {
|
|
|
42
42
|
inputRef?: ForwardedRef<HTMLInputElement>;
|
|
43
43
|
setInputRef?: (ref: ForwardedRef<HTMLInputElement>) => void;
|
|
44
44
|
setLabelWidth?: (width: number) => void;
|
|
45
|
+
setButtonWidth?: (width: number) => void;
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
const InputFieldContext = createContext<InputFieldContextValue>({
|
|
48
49
|
labelPosition: "end",
|
|
49
|
-
labelSize:
|
|
50
|
-
|
|
50
|
+
labelSize: undefined,
|
|
51
|
+
buttonSize: undefined,
|
|
51
52
|
hasDropdown: false,
|
|
52
53
|
size: "medium",
|
|
53
54
|
isFocused: false,
|
|
@@ -62,26 +63,31 @@ const LabelContainer = styled.label<{
|
|
|
62
63
|
pointerEvents: Property.PointerEvents;
|
|
63
64
|
$labelPosition: LabelPosition;
|
|
64
65
|
$hasDropdown: boolean;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
66
|
+
$size: InputFieldSize;
|
|
67
|
+
}>(({ theme, $labelPosition, $hasDropdown, pointerEvents, $size }) => {
|
|
68
|
+
const offsetRelativeToSize =
|
|
69
|
+
$size === "large" ? 6 : $size === "medium" ? 2 : 0;
|
|
70
|
+
return {
|
|
71
|
+
...theme.textStyles.label,
|
|
72
|
+
fontWeight: "bold",
|
|
73
|
+
color: theme.colors.textDisabled,
|
|
74
|
+
position: "absolute",
|
|
75
|
+
top: 0,
|
|
76
|
+
bottom: 0,
|
|
77
|
+
right: $labelPosition === "end" ? offsetRelativeToSize : undefined,
|
|
78
|
+
left: $labelPosition === "start" ? offsetRelativeToSize : undefined,
|
|
79
|
+
display: "flex",
|
|
80
|
+
alignItems: "center",
|
|
81
|
+
pointerEvents,
|
|
82
|
+
userSelect: "none",
|
|
83
|
+
...($labelPosition === "start"
|
|
84
|
+
? { justifyContent: "flex-start", paddingLeft: "6px" }
|
|
85
|
+
: {
|
|
86
|
+
justifyContent: "flex-end",
|
|
87
|
+
paddingRight: $hasDropdown ? "16px" : "6px",
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
});
|
|
85
91
|
|
|
86
92
|
interface InputFieldLabelProps {
|
|
87
93
|
children?: ReactNode;
|
|
@@ -89,12 +95,13 @@ interface InputFieldLabelProps {
|
|
|
89
95
|
style?: React.CSSProperties;
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
/** Inserts a Label at the start or end of the input given a `labelPosition`on InputField.Root. Should not be used with an InputField.Button */
|
|
92
99
|
const InputFieldLabel = memo(
|
|
93
100
|
forwardRef(function InputFieldLabel(
|
|
94
101
|
{ children = false, pointerEvents = "none", style }: InputFieldLabelProps,
|
|
95
102
|
forwardedRef: ForwardedRef<HTMLLabelElement>
|
|
96
103
|
) {
|
|
97
|
-
const { labelPosition, hasDropdown, setLabelWidth } =
|
|
104
|
+
const { labelPosition, hasDropdown, setLabelWidth, size } =
|
|
98
105
|
useContext(InputFieldContext);
|
|
99
106
|
|
|
100
107
|
const ref = useRef<HTMLLabelElement | null>(null);
|
|
@@ -111,6 +118,7 @@ const InputFieldLabel = memo(
|
|
|
111
118
|
|
|
112
119
|
return (
|
|
113
120
|
<LabelContainer
|
|
121
|
+
$size={size}
|
|
114
122
|
ref={(element) => {
|
|
115
123
|
ref.current = element;
|
|
116
124
|
assignRef(forwardedRef, element);
|
|
@@ -180,51 +188,74 @@ const ButtonContainer = styled.span<{ $size: InputFieldSize }>(
|
|
|
180
188
|
({ theme, $size }) => ({
|
|
181
189
|
position: "absolute",
|
|
182
190
|
right: $size === "large" ? "9px" : $size === "medium" ? "4px" : "2px",
|
|
183
|
-
top: $size === "large" ? "
|
|
191
|
+
top: $size === "large" ? "10px" : $size === "medium" ? "4px" : "2px",
|
|
184
192
|
})
|
|
185
193
|
);
|
|
186
194
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
/** Inserts a Button at the end of the input. Should not be used with an InputField.Label */
|
|
196
|
+
const InputFieldButton = memo(
|
|
197
|
+
forwardRef(function InputFieldButton(
|
|
198
|
+
{
|
|
199
|
+
children,
|
|
200
|
+
onClick,
|
|
201
|
+
}: {
|
|
202
|
+
children?: ReactNode;
|
|
203
|
+
onClick?: () => void;
|
|
204
|
+
},
|
|
205
|
+
forwardedRef: ForwardedRef<HTMLButtonElement>
|
|
206
|
+
) {
|
|
207
|
+
const { size, inputRef, setButtonWidth } = useContext(InputFieldContext);
|
|
208
|
+
|
|
209
|
+
const ref = useRef<HTMLButtonElement | null>(null);
|
|
210
|
+
|
|
211
|
+
useLayoutEffect(() => {
|
|
212
|
+
if (!setButtonWidth) return;
|
|
213
|
+
|
|
214
|
+
const width = ref.current?.getBoundingClientRect().width;
|
|
215
|
+
|
|
216
|
+
if (!width) return;
|
|
203
217
|
|
|
218
|
+
setButtonWidth(width);
|
|
219
|
+
}, [setButtonWidth]);
|
|
220
|
+
|
|
221
|
+
const defaultHandleClick = useCallback(
|
|
222
|
+
(event: React.MouseEvent) => {
|
|
223
|
+
if (inputRef && typeof inputRef !== "function") {
|
|
224
|
+
inputRef.current?.focus();
|
|
225
|
+
// Select all text
|
|
226
|
+
inputRef.current?.setSelectionRange(0, inputRef.current.value.length);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
event.preventDefault();
|
|
230
|
+
event.stopPropagation();
|
|
231
|
+
},
|
|
232
|
+
[inputRef]
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
const handlePointerDown = useCallback((event: React.PointerEvent) => {
|
|
204
236
|
event.preventDefault();
|
|
205
237
|
event.stopPropagation();
|
|
206
|
-
},
|
|
207
|
-
[inputRef]
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
const handlePointerDown = useCallback((event: React.PointerEvent) => {
|
|
211
|
-
event.preventDefault();
|
|
212
|
-
event.stopPropagation();
|
|
213
|
-
}, []);
|
|
238
|
+
}, []);
|
|
214
239
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
240
|
+
return (
|
|
241
|
+
<ButtonContainer $size={size}>
|
|
242
|
+
<Button
|
|
243
|
+
ref={(element) => {
|
|
244
|
+
ref.current = element;
|
|
245
|
+
assignRef(forwardedRef, element);
|
|
246
|
+
}}
|
|
247
|
+
variant="floating"
|
|
248
|
+
onClick={onClick ?? defaultHandleClick}
|
|
249
|
+
onPointerDown={handlePointerDown}
|
|
250
|
+
tabIndex={-1}
|
|
251
|
+
size={size === "medium" ? "normal" : size}
|
|
252
|
+
>
|
|
253
|
+
{children}
|
|
254
|
+
</Button>
|
|
255
|
+
</ButtonContainer>
|
|
256
|
+
);
|
|
257
|
+
})
|
|
258
|
+
);
|
|
228
259
|
|
|
229
260
|
/* ----------------------------------------------------------------------------
|
|
230
261
|
* Input
|
|
@@ -243,8 +274,7 @@ export const InputElement = styled(TextInput)<{
|
|
|
243
274
|
disabled?: boolean;
|
|
244
275
|
readOnly?: boolean;
|
|
245
276
|
$labelPosition: LabelPosition;
|
|
246
|
-
$labelSize
|
|
247
|
-
$hasLabel: boolean;
|
|
277
|
+
$labelSize?: number;
|
|
248
278
|
$hasDropdown: boolean;
|
|
249
279
|
$textAlign?: Property.TextAlign;
|
|
250
280
|
$variant?: InputFieldVariant;
|
|
@@ -256,7 +286,6 @@ export const InputElement = styled(TextInput)<{
|
|
|
256
286
|
$hasDropdown,
|
|
257
287
|
$textAlign,
|
|
258
288
|
disabled,
|
|
259
|
-
$hasLabel,
|
|
260
289
|
readOnly,
|
|
261
290
|
$variant = "normal",
|
|
262
291
|
$size,
|
|
@@ -289,11 +318,11 @@ export const InputElement = styled(TextInput)<{
|
|
|
289
318
|
$size === "large" ? "10px" : $size === "medium" ? "4px" : "1px",
|
|
290
319
|
paddingLeft:
|
|
291
320
|
($size === "large" ? 10 : $size === "medium" ? 6 : 4) +
|
|
292
|
-
($
|
|
321
|
+
($labelSize && $labelPosition === "start" ? 6 + $labelSize : 0) +
|
|
293
322
|
"px",
|
|
294
323
|
paddingRight:
|
|
295
324
|
($size === "large" ? 10 : $size === "medium" ? 6 : 4) +
|
|
296
|
-
($
|
|
325
|
+
($labelSize && $labelPosition === "end" ? 6 + $labelSize : 0) +
|
|
297
326
|
($hasDropdown ? 11 : 0) +
|
|
298
327
|
"px",
|
|
299
328
|
background: theme.colors.inputBackground,
|
|
@@ -322,6 +351,7 @@ export const InputElement = styled(TextInput)<{
|
|
|
322
351
|
};
|
|
323
352
|
});
|
|
324
353
|
|
|
354
|
+
/** Should always be wrapped in InputField.Root */
|
|
325
355
|
const InputFieldInput = forwardRef(function InputFieldInput(
|
|
326
356
|
// onFocusChange should only be passed from the root, never directly
|
|
327
357
|
{
|
|
@@ -338,7 +368,7 @@ const InputFieldInput = forwardRef(function InputFieldInput(
|
|
|
338
368
|
labelPosition,
|
|
339
369
|
labelSize,
|
|
340
370
|
hasDropdown,
|
|
341
|
-
|
|
371
|
+
buttonSize,
|
|
342
372
|
size,
|
|
343
373
|
onFocusChange,
|
|
344
374
|
setInputRef,
|
|
@@ -359,8 +389,7 @@ const InputFieldInput = forwardRef(function InputFieldInput(
|
|
|
359
389
|
<InputElement
|
|
360
390
|
ref={forwardedRef}
|
|
361
391
|
$labelPosition={labelPosition}
|
|
362
|
-
$labelSize={labelSize}
|
|
363
|
-
$hasLabel={hasLabel}
|
|
392
|
+
$labelSize={labelSize || buttonSize}
|
|
364
393
|
$hasDropdown={hasDropdown}
|
|
365
394
|
$size={size}
|
|
366
395
|
$variant={variant}
|
|
@@ -376,7 +405,6 @@ const InputFieldTypeahead = (props: { prefix: string; value: string }) => {
|
|
|
376
405
|
labelPosition,
|
|
377
406
|
labelSize,
|
|
378
407
|
hasDropdown,
|
|
379
|
-
hasLabel,
|
|
380
408
|
size,
|
|
381
409
|
// onFocusChange,
|
|
382
410
|
} = useContext(InputFieldContext);
|
|
@@ -386,7 +414,6 @@ const InputFieldTypeahead = (props: { prefix: string; value: string }) => {
|
|
|
386
414
|
as="span"
|
|
387
415
|
$labelPosition={labelPosition}
|
|
388
416
|
$labelSize={labelSize}
|
|
389
|
-
$hasLabel={hasLabel}
|
|
390
417
|
$hasDropdown={hasDropdown}
|
|
391
418
|
$size={size}
|
|
392
419
|
// onFocusChange={onFocusChange}
|
|
@@ -529,15 +556,16 @@ function InputFieldNumberInput(props: InputFieldNumberInputProps) {
|
|
|
529
556
|
* Root
|
|
530
557
|
* ------------------------------------------------------------------------- */
|
|
531
558
|
|
|
532
|
-
const RootContainer = styled.div<{
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
559
|
+
const RootContainer = styled.div<{
|
|
560
|
+
$width?: number;
|
|
561
|
+
$flex?: string;
|
|
562
|
+
}>(({ theme, $flex, $width }) => ({
|
|
563
|
+
flex: $flex ?? "1",
|
|
564
|
+
display: "flex",
|
|
565
|
+
flexDirection: "row",
|
|
566
|
+
position: "relative",
|
|
567
|
+
maxWidth: typeof $width === "number" ? `${$width}px` : undefined,
|
|
568
|
+
}));
|
|
541
569
|
|
|
542
570
|
interface InputFieldRootProps {
|
|
543
571
|
id?: string;
|
|
@@ -574,13 +602,11 @@ function InputFieldRoot({
|
|
|
574
602
|
const hasDropdown = childrenArray.some(
|
|
575
603
|
(child) => isValidElement(child) && child.type === InputFieldDropdownMenu
|
|
576
604
|
);
|
|
577
|
-
const hasLabel = childrenArray.some(
|
|
578
|
-
(child) => isValidElement(child) && child.type === InputFieldLabel
|
|
579
|
-
);
|
|
580
605
|
|
|
581
606
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
582
607
|
|
|
583
608
|
const [measuredLabelSize, setMeasuredLabelSize] = React.useState<number>();
|
|
609
|
+
const [measuredButtonSize, setMeasuredButtonSize] = React.useState<number>();
|
|
584
610
|
const [measuredWidth, setMeasuredWidth] = React.useState<number>();
|
|
585
611
|
|
|
586
612
|
const handleFocusChange = useCallback(
|
|
@@ -606,22 +632,23 @@ function InputFieldRoot({
|
|
|
606
632
|
const contextValue = useMemo(
|
|
607
633
|
(): InputFieldContextValue => ({
|
|
608
634
|
labelPosition,
|
|
609
|
-
labelSize: measuredLabelSize ?? labelSize
|
|
635
|
+
labelSize: measuredLabelSize ?? labelSize,
|
|
636
|
+
buttonSize: measuredButtonSize,
|
|
610
637
|
hasDropdown,
|
|
611
|
-
hasLabel,
|
|
612
638
|
size,
|
|
613
639
|
isFocused,
|
|
614
640
|
onFocusChange: handleFocusChange,
|
|
615
641
|
inputRef,
|
|
616
642
|
setInputRef,
|
|
617
643
|
setLabelWidth: setMeasuredLabelSize,
|
|
644
|
+
setButtonWidth: setMeasuredButtonSize,
|
|
618
645
|
}),
|
|
619
646
|
[
|
|
620
647
|
labelPosition,
|
|
621
648
|
measuredLabelSize,
|
|
622
649
|
labelSize,
|
|
650
|
+
measuredButtonSize,
|
|
623
651
|
hasDropdown,
|
|
624
|
-
hasLabel,
|
|
625
652
|
size,
|
|
626
653
|
isFocused,
|
|
627
654
|
handleFocusChange,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { DropdownChevronIcon } from "@noya-app/noya-icons";
|
|
2
2
|
import * as Select from "@radix-ui/react-select";
|
|
3
|
-
import
|
|
3
|
+
import { type SelectProps } from "@radix-ui/react-select";
|
|
4
|
+
import React, { CSSProperties, memo, useMemo } from "react";
|
|
4
5
|
import { styled } from "styled-components";
|
|
5
6
|
import { Button } from "./Button";
|
|
6
7
|
import { renderIcon } from "./Icons";
|
|
7
8
|
import { Spacer } from "./Spacer";
|
|
8
9
|
import { MenuItem, RegularMenuItem, styles } from "./internal/Menu";
|
|
10
|
+
import { Stack } from "./Stack";
|
|
9
11
|
|
|
10
12
|
type Props<T extends string> = {
|
|
11
13
|
id?: string;
|
|
@@ -17,7 +19,8 @@ type Props<T extends string> = {
|
|
|
17
19
|
placeholder?: string;
|
|
18
20
|
disabled?: boolean;
|
|
19
21
|
readOnly?: boolean;
|
|
20
|
-
|
|
22
|
+
label?: React.ReactNode;
|
|
23
|
+
} & Pick<SelectProps, "open">;
|
|
21
24
|
|
|
22
25
|
const readOnlyStyle: CSSProperties = {
|
|
23
26
|
justifyContent: "flex-start",
|
|
@@ -28,6 +31,25 @@ const flexStyle: CSSProperties = {
|
|
|
28
31
|
flex: 1,
|
|
29
32
|
};
|
|
30
33
|
|
|
34
|
+
const textStyle: CSSProperties = {
|
|
35
|
+
fontSize: "0.85rem",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const SelectLabel = styled.label(({ theme }) => ({
|
|
39
|
+
...theme.textStyles.label,
|
|
40
|
+
color: theme.colors.textDisabled,
|
|
41
|
+
lineHeight: "19px",
|
|
42
|
+
position: "absolute",
|
|
43
|
+
inset: "0",
|
|
44
|
+
fontWeight: "bold",
|
|
45
|
+
fontSize: "60%",
|
|
46
|
+
pointerEvents: "none",
|
|
47
|
+
display: "flex",
|
|
48
|
+
alignItems: "center",
|
|
49
|
+
justifyContent: "end",
|
|
50
|
+
paddingRight: "24px",
|
|
51
|
+
}));
|
|
52
|
+
|
|
31
53
|
export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
32
54
|
id,
|
|
33
55
|
style,
|
|
@@ -38,6 +60,8 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
38
60
|
placeholder,
|
|
39
61
|
disabled,
|
|
40
62
|
readOnly,
|
|
63
|
+
label,
|
|
64
|
+
open,
|
|
41
65
|
}: Props<T>) {
|
|
42
66
|
const selectedItem = menuItems.find(
|
|
43
67
|
(item): item is RegularMenuItem<T> =>
|
|
@@ -45,11 +69,11 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
45
69
|
);
|
|
46
70
|
const icon = selectedItem?.icon;
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
|
|
72
|
+
const readOnlyButton = useMemo(
|
|
73
|
+
() => (
|
|
50
74
|
<Button
|
|
51
75
|
id={id}
|
|
52
|
-
style={style}
|
|
76
|
+
style={{ ...style, ...flexStyle }}
|
|
53
77
|
contentStyle={readOnlyStyle}
|
|
54
78
|
className={className}
|
|
55
79
|
disabled={disabled}
|
|
@@ -60,15 +84,23 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
60
84
|
<Spacer.Horizontal inline size={6} />
|
|
61
85
|
</>
|
|
62
86
|
)}
|
|
63
|
-
<span style={
|
|
87
|
+
<span style={{ ...flexStyle, ...textStyle }}>
|
|
88
|
+
{selectedItem?.title ?? value}
|
|
89
|
+
</span>
|
|
64
90
|
</Button>
|
|
65
|
-
)
|
|
66
|
-
|
|
91
|
+
),
|
|
92
|
+
[icon, id, style, className, disabled, value, selectedItem]
|
|
93
|
+
);
|
|
67
94
|
|
|
68
|
-
|
|
69
|
-
|
|
95
|
+
const trigger = useMemo(
|
|
96
|
+
() => (
|
|
70
97
|
<Select.SelectTrigger asChild>
|
|
71
|
-
<Button
|
|
98
|
+
<Button
|
|
99
|
+
id={id}
|
|
100
|
+
style={{ ...textStyle, ...style, ...flexStyle }}
|
|
101
|
+
className={className}
|
|
102
|
+
disabled={disabled}
|
|
103
|
+
>
|
|
72
104
|
{icon && (
|
|
73
105
|
<>
|
|
74
106
|
{renderIcon(icon)}
|
|
@@ -82,6 +114,31 @@ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
|
|
|
82
114
|
<DropdownChevronIcon />
|
|
83
115
|
</Button>
|
|
84
116
|
</Select.SelectTrigger>
|
|
117
|
+
),
|
|
118
|
+
[icon, id, style, className, disabled, placeholder]
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (readOnly) {
|
|
122
|
+
return label ? (
|
|
123
|
+
<Stack.V position="relative">
|
|
124
|
+
{readOnlyButton}
|
|
125
|
+
<SelectLabel htmlFor={id}>{label}</SelectLabel>
|
|
126
|
+
</Stack.V>
|
|
127
|
+
) : (
|
|
128
|
+
readOnlyButton
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<Select.Root value={value} onValueChange={onSelect} open={open}>
|
|
134
|
+
{label ? (
|
|
135
|
+
<Stack.V position="relative" style={flexStyle}>
|
|
136
|
+
{trigger}
|
|
137
|
+
<SelectLabel htmlFor={id}>{label}</SelectLabel>
|
|
138
|
+
</Stack.V>
|
|
139
|
+
) : (
|
|
140
|
+
trigger
|
|
141
|
+
)}
|
|
85
142
|
<Select.Portal>
|
|
86
143
|
<SelectContent>
|
|
87
144
|
<SelectViewport>
|
|
@@ -126,7 +183,7 @@ const SelectItem = React.forwardRef(
|
|
|
126
183
|
<Spacer.Horizontal size={8} />
|
|
127
184
|
</>
|
|
128
185
|
)}
|
|
129
|
-
<Select.ItemText>{children}</Select.ItemText>
|
|
186
|
+
<Select.ItemText style={textStyle}>{children}</Select.ItemText>
|
|
130
187
|
</StyledItem>
|
|
131
188
|
);
|
|
132
189
|
}
|
package/src/components/Stack.tsx
CHANGED
|
@@ -12,7 +12,7 @@ import { BreakpointCollection, mergeBreakpoints } from "../utils/breakpoints";
|
|
|
12
12
|
import withSeparatorElements from "../utils/withSeparatorElements";
|
|
13
13
|
|
|
14
14
|
interface StyleProps {
|
|
15
|
-
display?: "
|
|
15
|
+
display?: CSSProperties["display"];
|
|
16
16
|
visibility?: CSSProperties["visibility"];
|
|
17
17
|
position?: CSSProperties["position"];
|
|
18
18
|
zIndex?: CSSProperties["zIndex"];
|
|
@@ -78,6 +78,7 @@ interface Props extends StyleProps {
|
|
|
78
78
|
breakpoints?: StackBreakpointList | null | false;
|
|
79
79
|
href?: string; // Shouldn't be here, ideally
|
|
80
80
|
tabIndex?: number;
|
|
81
|
+
style?: StyleProps;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
const Element = styled.div<{
|
|
@@ -98,6 +99,10 @@ const StackBase = forwardRef(function StackBase(
|
|
|
98
99
|
breakpoints,
|
|
99
100
|
tabIndex,
|
|
100
101
|
href,
|
|
102
|
+
paddingHorizontal,
|
|
103
|
+
paddingVertical,
|
|
104
|
+
padding,
|
|
105
|
+
style,
|
|
101
106
|
...rest
|
|
102
107
|
}: Props,
|
|
103
108
|
forwardedRef: ForwardedRef<HTMLElement>
|
|
@@ -110,7 +115,11 @@ const StackBase = forwardRef(function StackBase(
|
|
|
110
115
|
display: "flex",
|
|
111
116
|
position: "relative",
|
|
112
117
|
alignItems: "stretch",
|
|
118
|
+
padding:
|
|
119
|
+
padding ||
|
|
120
|
+
`${paddingVertical ?? 0} ${paddingHorizontal ?? 0} ${paddingVertical ?? 0} ${paddingHorizontal ?? 0}`,
|
|
113
121
|
...rest,
|
|
122
|
+
...style,
|
|
114
123
|
};
|
|
115
124
|
|
|
116
125
|
return (
|
|
@@ -3,7 +3,13 @@ import {
|
|
|
3
3
|
useDesignSystemTheme,
|
|
4
4
|
} from "@noya-app/noya-designsystem";
|
|
5
5
|
import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
|
|
6
|
-
import React, {
|
|
6
|
+
import React, {
|
|
7
|
+
forwardRef,
|
|
8
|
+
useCallback,
|
|
9
|
+
useImperativeHandle,
|
|
10
|
+
useRef,
|
|
11
|
+
useState,
|
|
12
|
+
} from "react";
|
|
7
13
|
import {
|
|
8
14
|
ImperativePanelGroupHandle,
|
|
9
15
|
ImperativePanelHandle,
|
|
@@ -98,7 +104,17 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
98
104
|
const leftSidebarRef = useRef<ImperativePanelHandle>(null);
|
|
99
105
|
const rightSidebarRef = useRef<ImperativePanelHandle>(null);
|
|
100
106
|
|
|
101
|
-
|
|
107
|
+
const [internalLayoutState, setInternalLayoutState] =
|
|
108
|
+
useState<PanelLayoutState | null>(null);
|
|
109
|
+
const handleChangeLayoutState = useCallback(
|
|
110
|
+
(state: PanelLayoutState) => {
|
|
111
|
+
setInternalLayoutState(state);
|
|
112
|
+
onChangeLayoutState?.(state);
|
|
113
|
+
},
|
|
114
|
+
[onChangeLayoutState]
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
usePreservePanelSize(panelGroupRef, handleChangeLayoutState);
|
|
102
118
|
|
|
103
119
|
const theme = useDesignSystemTheme();
|
|
104
120
|
|
|
@@ -207,7 +223,9 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
207
223
|
position: "relative",
|
|
208
224
|
}}
|
|
209
225
|
>
|
|
210
|
-
{
|
|
226
|
+
{internalLayoutState?.leftSidebarCollapsed
|
|
227
|
+
? null
|
|
228
|
+
: leftPanelContent}
|
|
211
229
|
</Panel>
|
|
212
230
|
<PanelResizeHandle
|
|
213
231
|
style={{
|
|
@@ -255,7 +273,9 @@ const WorkspaceLayoutWithTheme = forwardRef(function WorkspaceLayoutWithTheme(
|
|
|
255
273
|
position: "relative",
|
|
256
274
|
}}
|
|
257
275
|
>
|
|
258
|
-
{
|
|
276
|
+
{internalLayoutState?.rightSidebarCollapsed
|
|
277
|
+
? null
|
|
278
|
+
: rightPanelContent}
|
|
259
279
|
</Panel>
|
|
260
280
|
</>
|
|
261
281
|
)}
|
package/src/index.tsx
CHANGED
|
@@ -41,7 +41,6 @@ export * from "./components/Popover";
|
|
|
41
41
|
export * from "./components/Progress";
|
|
42
42
|
export * from "./components/RadioGroup";
|
|
43
43
|
export * from "./components/ScrollArea";
|
|
44
|
-
export * from "./components/Select";
|
|
45
44
|
export * from "./components/SelectMenu";
|
|
46
45
|
export * from "./components/Slider";
|
|
47
46
|
export * from "./components/Sortable";
|
|
@@ -76,6 +75,7 @@ export * as darkTheme from "./theme/dark";
|
|
|
76
75
|
export * as lightTheme from "./theme/light";
|
|
77
76
|
export * from "./utils/createSectionedMenu";
|
|
78
77
|
export * from "./utils/getGradientBackground";
|
|
78
|
+
export * from "./hooks/usePreservePanelSize";
|
|
79
79
|
// Utils
|
|
80
80
|
export * from "./utils/completions";
|
|
81
81
|
export * from "./utils/fuzzyScorer";
|