@noya-app/noya-designsystem 0.1.42 → 0.1.44
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/CHANGELOG.md +12 -0
- package/dist/index.css +1 -1
- package/dist/index.d.mts +62 -36
- package/dist/index.d.ts +62 -36
- package/dist/index.js +226 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +234 -143
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Combobox.tsx +158 -52
- package/src/components/SelectMenu.tsx +4 -0
- package/src/components/TextArea.tsx +61 -24
- package/src/components/Toolbar.tsx +4 -9
- package/src/components/WorkspaceLayout.tsx +145 -152
package/package.json
CHANGED
|
@@ -25,17 +25,12 @@ import { InputField, InputFieldSize } from "./InputField";
|
|
|
25
25
|
import { ListView } from "./ListView";
|
|
26
26
|
import { Small } from "./Text";
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type BaseComboboxProps = {
|
|
29
29
|
id?: string;
|
|
30
30
|
loading?: boolean;
|
|
31
|
-
initialValue?: string;
|
|
32
31
|
placeholder?: string;
|
|
33
32
|
items: ComboboxItem[];
|
|
34
|
-
onChange?: (value: string) => void;
|
|
35
|
-
onHoverItem?: (item: ComboboxOption | undefined) => void;
|
|
36
|
-
onSelectItem?: (item: ComboboxOption) => void;
|
|
37
33
|
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
38
|
-
onBlur?: (didSubmit: boolean, value: string) => void;
|
|
39
34
|
onDeleteWhenEmpty?: () => void;
|
|
40
35
|
size?: InputFieldSize;
|
|
41
36
|
style?: React.CSSProperties;
|
|
@@ -43,15 +38,40 @@ export type ComboboxProps = {
|
|
|
43
38
|
label?: React.ReactNode;
|
|
44
39
|
children?: React.ReactNode;
|
|
45
40
|
hideMenuWhenEmptyValue?: boolean;
|
|
46
|
-
allowArbitraryValues?: boolean;
|
|
47
41
|
readOnly?: boolean;
|
|
48
42
|
tabBehavior?: "autocomplete" | "select";
|
|
49
43
|
openMenuBehavior?: "showAllItems" | "showFilteredItems";
|
|
50
44
|
};
|
|
51
45
|
|
|
46
|
+
export type StringModeOnlyProps = {
|
|
47
|
+
mode: "string";
|
|
48
|
+
value?: string;
|
|
49
|
+
onChange?: (value: string) => void;
|
|
50
|
+
onSelectItem?: (value: string) => void;
|
|
51
|
+
onBlur?: (didSubmit: boolean, value: string) => void;
|
|
52
|
+
onHoverItem?: (value: string | undefined) => void;
|
|
53
|
+
allowArbitraryValues?: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type StringModeProps = BaseComboboxProps & StringModeOnlyProps;
|
|
57
|
+
|
|
58
|
+
export type OptionModeOnlyProps = {
|
|
59
|
+
mode?: "option";
|
|
60
|
+
value?: ComboboxOption;
|
|
61
|
+
onChange?: (value: ComboboxOption) => void;
|
|
62
|
+
onSelectItem?: (value: ComboboxOption) => void;
|
|
63
|
+
onBlur?: (didSubmit: boolean, value: ComboboxOption) => void;
|
|
64
|
+
onHoverItem?: (value: ComboboxOption | undefined) => void;
|
|
65
|
+
allowArbitraryValues?: false;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type OptionModeProps = BaseComboboxProps & OptionModeOnlyProps;
|
|
69
|
+
|
|
70
|
+
export type ComboboxProps = StringModeProps | OptionModeProps;
|
|
71
|
+
|
|
52
72
|
export interface ComboboxRef {
|
|
53
73
|
focus(): void;
|
|
54
|
-
setValue(value: string): void;
|
|
74
|
+
setValue(value: string | ComboboxOption): void;
|
|
55
75
|
selectAllInputText(): void;
|
|
56
76
|
}
|
|
57
77
|
|
|
@@ -60,31 +80,75 @@ export const Combobox = memo(
|
|
|
60
80
|
{
|
|
61
81
|
id,
|
|
62
82
|
loading,
|
|
63
|
-
initialValue = "",
|
|
64
83
|
placeholder,
|
|
65
84
|
items,
|
|
66
85
|
size,
|
|
67
|
-
onChange,
|
|
68
|
-
onSelectItem,
|
|
69
|
-
onHoverItem,
|
|
70
|
-
onFocus,
|
|
71
|
-
onBlur,
|
|
72
|
-
onDeleteWhenEmpty,
|
|
73
86
|
style,
|
|
74
87
|
className,
|
|
75
88
|
label,
|
|
76
89
|
children,
|
|
77
90
|
hideMenuWhenEmptyValue = false,
|
|
78
|
-
allowArbitraryValues = false,
|
|
79
91
|
readOnly = false,
|
|
80
92
|
tabBehavior = "select",
|
|
81
93
|
openMenuBehavior = "showFilteredItems",
|
|
94
|
+
onFocus,
|
|
95
|
+
onDeleteWhenEmpty,
|
|
96
|
+
...rest
|
|
82
97
|
}: ComboboxProps,
|
|
83
98
|
forwardedRef: ForwardedRef<ComboboxRef>
|
|
84
99
|
) {
|
|
100
|
+
// We make a separate props object for the mode-specific props for memoizing
|
|
101
|
+
// since we put the props object into hook deps
|
|
102
|
+
const props = useMemo((): StringModeOnlyProps | OptionModeOnlyProps => {
|
|
103
|
+
if (rest.mode === "string") {
|
|
104
|
+
return {
|
|
105
|
+
mode: rest.mode,
|
|
106
|
+
value: rest.value,
|
|
107
|
+
onChange: rest.onChange,
|
|
108
|
+
onSelectItem: rest.onSelectItem,
|
|
109
|
+
onHoverItem: rest.onHoverItem,
|
|
110
|
+
onBlur: rest.onBlur,
|
|
111
|
+
allowArbitraryValues: rest.allowArbitraryValues,
|
|
112
|
+
} satisfies StringModeOnlyProps;
|
|
113
|
+
} else {
|
|
114
|
+
return {
|
|
115
|
+
mode: rest.mode,
|
|
116
|
+
value: rest.value,
|
|
117
|
+
onChange: rest.onChange,
|
|
118
|
+
onSelectItem: rest.onSelectItem,
|
|
119
|
+
onHoverItem: rest.onHoverItem,
|
|
120
|
+
onBlur: rest.onBlur,
|
|
121
|
+
} satisfies OptionModeOnlyProps;
|
|
122
|
+
}
|
|
123
|
+
}, [
|
|
124
|
+
rest.mode,
|
|
125
|
+
rest.value,
|
|
126
|
+
rest.onChange,
|
|
127
|
+
rest.onSelectItem,
|
|
128
|
+
rest.onHoverItem,
|
|
129
|
+
rest.onBlur,
|
|
130
|
+
rest.allowArbitraryValues,
|
|
131
|
+
]);
|
|
132
|
+
|
|
85
133
|
const ref = useRef<HTMLInputElement>(null);
|
|
134
|
+
|
|
135
|
+
function getInitialValueString() {
|
|
136
|
+
if (props.mode === "string") {
|
|
137
|
+
return props.value ?? "";
|
|
138
|
+
} else {
|
|
139
|
+
return props.value?.name ?? "";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const initialValueString = getInitialValueString();
|
|
144
|
+
|
|
86
145
|
const [comboboxState] = useState(
|
|
87
|
-
() =>
|
|
146
|
+
() =>
|
|
147
|
+
new ComboboxState(
|
|
148
|
+
items,
|
|
149
|
+
initialValueString,
|
|
150
|
+
props.mode === "string" && (props.allowArbitraryValues ?? false)
|
|
151
|
+
)
|
|
88
152
|
);
|
|
89
153
|
const state = useComboboxState(comboboxState);
|
|
90
154
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -96,13 +160,14 @@ export const Combobox = memo(
|
|
|
96
160
|
comboboxState.setItems(items);
|
|
97
161
|
}, [items, comboboxState]);
|
|
98
162
|
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
comboboxState.setFilter(initialValueString);
|
|
165
|
+
}, [comboboxState, initialValueString]);
|
|
166
|
+
|
|
99
167
|
const { filter, selectedIndex, filteredItems } = state;
|
|
100
168
|
|
|
101
|
-
const shouldShowMenu =
|
|
102
|
-
|
|
103
|
-
if (hideMenuWhenEmptyValue && filter === "") return false;
|
|
104
|
-
return true;
|
|
105
|
-
}, [hideMenuWhenEmptyValue, filter, isFocused]);
|
|
169
|
+
const shouldShowMenu =
|
|
170
|
+
isFocused && !(hideMenuWhenEmptyValue && filter === "");
|
|
106
171
|
|
|
107
172
|
useEffect(() => {
|
|
108
173
|
if (listRef.current) {
|
|
@@ -112,16 +177,29 @@ export const Combobox = memo(
|
|
|
112
177
|
|
|
113
178
|
const handleBlur = useCallback(() => {
|
|
114
179
|
ref.current?.blur();
|
|
115
|
-
comboboxState.reset(
|
|
116
|
-
|
|
180
|
+
comboboxState.reset(initialValueString);
|
|
181
|
+
if (props.mode === "string") {
|
|
182
|
+
props.onBlur?.(
|
|
183
|
+
state.filter === state.lastSubmittedValue.filter,
|
|
184
|
+
filter
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
const selectedItem = comboboxState.getSelectedItem();
|
|
188
|
+
if (selectedItem && selectedItem.type !== "sectionHeader") {
|
|
189
|
+
props.onBlur?.(
|
|
190
|
+
state.filter === state.lastSubmittedValue.filter,
|
|
191
|
+
selectedItem
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
117
195
|
setIsFocused(false);
|
|
118
|
-
}, [filter,
|
|
196
|
+
}, [filter, initialValueString, props, state, comboboxState]);
|
|
119
197
|
|
|
120
198
|
const handleFocus: FocusEventHandler<HTMLInputElement> = useCallback(
|
|
121
199
|
(event) => {
|
|
122
200
|
setIsFocused(true);
|
|
123
201
|
comboboxState.reset(
|
|
124
|
-
openMenuBehavior === "showAllItems" ? "" :
|
|
202
|
+
openMenuBehavior === "showAllItems" ? "" : initialValueString
|
|
125
203
|
);
|
|
126
204
|
if (ref.current) {
|
|
127
205
|
const length = ref.current.value.length;
|
|
@@ -129,7 +207,7 @@ export const Combobox = memo(
|
|
|
129
207
|
}
|
|
130
208
|
onFocus?.(event);
|
|
131
209
|
},
|
|
132
|
-
[
|
|
210
|
+
[initialValueString, onFocus, openMenuBehavior, comboboxState]
|
|
133
211
|
);
|
|
134
212
|
|
|
135
213
|
const handleUpdateSelection = useCallback(
|
|
@@ -139,11 +217,16 @@ export const Combobox = memo(
|
|
|
139
217
|
const selectedItem = comboboxState.selectCurrentItem(item);
|
|
140
218
|
if (!selectedItem || selectedItem.type === "sectionHeader") return;
|
|
141
219
|
|
|
142
|
-
|
|
143
|
-
|
|
220
|
+
if (props.mode === "string") {
|
|
221
|
+
props.onSelectItem?.(selectedItem.name);
|
|
222
|
+
props.onHoverItem?.(undefined);
|
|
223
|
+
} else {
|
|
224
|
+
props.onSelectItem?.(selectedItem);
|
|
225
|
+
props.onHoverItem?.(undefined);
|
|
226
|
+
}
|
|
144
227
|
setShouldBlur(true);
|
|
145
228
|
},
|
|
146
|
-
[
|
|
229
|
+
[props, comboboxState]
|
|
147
230
|
);
|
|
148
231
|
|
|
149
232
|
const handleIndexChange = useCallback(
|
|
@@ -151,12 +234,32 @@ export const Combobox = memo(
|
|
|
151
234
|
comboboxState.setSelectedIndex(index);
|
|
152
235
|
const item = comboboxState.getSelectedItem();
|
|
153
236
|
if (item && item.type !== "sectionHeader") {
|
|
154
|
-
|
|
237
|
+
if (props.mode === "string") {
|
|
238
|
+
props.onHoverItem?.(item.name);
|
|
239
|
+
} else {
|
|
240
|
+
props.onHoverItem?.(item);
|
|
241
|
+
}
|
|
155
242
|
} else {
|
|
156
|
-
onHoverItem?.(undefined);
|
|
243
|
+
props.onHoverItem?.(undefined);
|
|
157
244
|
}
|
|
158
245
|
},
|
|
159
|
-
[
|
|
246
|
+
[props, comboboxState]
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const handleChange = useCallback(
|
|
250
|
+
(value: string) => {
|
|
251
|
+
if (readOnly) return;
|
|
252
|
+
comboboxState.setFilter(value);
|
|
253
|
+
if (props.mode === "string") {
|
|
254
|
+
props.onChange?.(value);
|
|
255
|
+
} else {
|
|
256
|
+
const selectedItem = comboboxState.getSelectedItem();
|
|
257
|
+
if (selectedItem && selectedItem.type !== "sectionHeader") {
|
|
258
|
+
props.onChange?.(selectedItem);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
[readOnly, props, comboboxState]
|
|
160
263
|
);
|
|
161
264
|
|
|
162
265
|
const handleKeyDown = useCallback(
|
|
@@ -177,8 +280,11 @@ export const Combobox = memo(
|
|
|
177
280
|
if (shouldShowMenu) {
|
|
178
281
|
if (item) {
|
|
179
282
|
handleUpdateSelection(item);
|
|
180
|
-
} else if (
|
|
181
|
-
|
|
283
|
+
} else if (
|
|
284
|
+
props.mode === "string" &&
|
|
285
|
+
props.allowArbitraryValues
|
|
286
|
+
) {
|
|
287
|
+
// If no item is selected but arbitrary filters are allowed in string mode,
|
|
182
288
|
// submit the current filter value
|
|
183
289
|
comboboxState.submitArbitraryFilter(filter);
|
|
184
290
|
handleBlur();
|
|
@@ -213,8 +319,12 @@ export const Combobox = memo(
|
|
|
213
319
|
}
|
|
214
320
|
handled = true;
|
|
215
321
|
}
|
|
216
|
-
} else if (
|
|
217
|
-
|
|
322
|
+
} else if (
|
|
323
|
+
props.mode === "string" &&
|
|
324
|
+
props.allowArbitraryValues &&
|
|
325
|
+
filter !== ""
|
|
326
|
+
) {
|
|
327
|
+
// Allow submitting arbitrary filter on Tab only in string mode
|
|
218
328
|
comboboxState.submitArbitraryFilter(filter);
|
|
219
329
|
handleBlur();
|
|
220
330
|
handled = true;
|
|
@@ -250,19 +360,10 @@ export const Combobox = memo(
|
|
|
250
360
|
shouldShowMenu,
|
|
251
361
|
comboboxState,
|
|
252
362
|
tabBehavior,
|
|
253
|
-
|
|
363
|
+
props,
|
|
254
364
|
]
|
|
255
365
|
);
|
|
256
366
|
|
|
257
|
-
const handleChange = useCallback(
|
|
258
|
-
(value: string) => {
|
|
259
|
-
if (readOnly) return;
|
|
260
|
-
comboboxState.setFilter(value);
|
|
261
|
-
onChange?.(value);
|
|
262
|
-
},
|
|
263
|
-
[onChange, readOnly, comboboxState]
|
|
264
|
-
);
|
|
265
|
-
|
|
266
367
|
const typeaheadValue = comboboxState.getTypeaheadValue();
|
|
267
368
|
|
|
268
369
|
useImperativeHandle(forwardedRef, () => ({
|
|
@@ -273,8 +374,12 @@ export const Combobox = memo(
|
|
|
273
374
|
ref.current.setSelectionRange(length, length);
|
|
274
375
|
}
|
|
275
376
|
},
|
|
276
|
-
setValue: (value: string) => {
|
|
277
|
-
|
|
377
|
+
setValue: (value: string | ComboboxOption) => {
|
|
378
|
+
if (typeof value === "string") {
|
|
379
|
+
comboboxState.setFilter(value);
|
|
380
|
+
} else {
|
|
381
|
+
comboboxState.setFilter(value.name);
|
|
382
|
+
}
|
|
278
383
|
},
|
|
279
384
|
selectAllInputText: () => {
|
|
280
385
|
ref.current?.setSelectionRange(0, ref.current.value.length);
|
|
@@ -292,14 +397,14 @@ export const Combobox = memo(
|
|
|
292
397
|
|
|
293
398
|
// Use openMenuBehavior consistently for both focus and chevron click
|
|
294
399
|
comboboxState.reset(
|
|
295
|
-
openMenuBehavior === "showAllItems" ? "" :
|
|
400
|
+
openMenuBehavior === "showAllItems" ? "" : initialValueString
|
|
296
401
|
);
|
|
297
402
|
ref.current?.focus();
|
|
298
403
|
},
|
|
299
404
|
[
|
|
300
405
|
shouldShowMenu,
|
|
301
406
|
openMenuBehavior,
|
|
302
|
-
|
|
407
|
+
initialValueString,
|
|
303
408
|
handleBlur,
|
|
304
409
|
comboboxState,
|
|
305
410
|
]
|
|
@@ -307,9 +412,10 @@ export const Combobox = memo(
|
|
|
307
412
|
|
|
308
413
|
useEffect(() => {
|
|
309
414
|
if (!shouldBlur) return;
|
|
415
|
+
if (document.activeElement !== ref.current) return;
|
|
416
|
+
setShouldBlur(false);
|
|
310
417
|
ref.current?.focus();
|
|
311
418
|
handleBlur();
|
|
312
|
-
setShouldBlur(false);
|
|
313
419
|
}, [shouldBlur, handleBlur]);
|
|
314
420
|
|
|
315
421
|
return (
|
|
@@ -31,6 +31,7 @@ type Props<T extends string> = {
|
|
|
31
31
|
label?: React.ReactNode;
|
|
32
32
|
onFocus?: FocusEventHandler;
|
|
33
33
|
onBlur?: FocusEventHandler;
|
|
34
|
+
contentStyle?: React.CSSProperties;
|
|
34
35
|
} & Pick<SelectProps, "open" | "onOpenChange">;
|
|
35
36
|
|
|
36
37
|
const readOnlyStyle: CSSProperties = {
|
|
@@ -68,6 +69,7 @@ export const SelectMenu = memoGeneric(function SelectMenu<
|
|
|
68
69
|
onFocus,
|
|
69
70
|
onBlur,
|
|
70
71
|
onOpenChange,
|
|
72
|
+
contentStyle,
|
|
71
73
|
}: Props<T>) {
|
|
72
74
|
const selectedItem = menuItems.find(
|
|
73
75
|
(item): item is RegularMenuItem<T> =>
|
|
@@ -184,6 +186,8 @@ export const SelectMenu = memoGeneric(function SelectMenu<
|
|
|
184
186
|
align="end"
|
|
185
187
|
style={{
|
|
186
188
|
width: "var(--radix-select-trigger-width)",
|
|
189
|
+
maxHeight: "500px",
|
|
190
|
+
...contentStyle,
|
|
187
191
|
}}
|
|
188
192
|
>
|
|
189
193
|
<Select.ScrollUpButton className={scrollButtonStyles}>
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { assignRef } from "@noya-app/react-utils";
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
ComponentProps,
|
|
4
|
+
forwardRef,
|
|
5
|
+
memo,
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useRef,
|
|
9
|
+
} from "react";
|
|
3
10
|
import { cx } from "../utils/classNames";
|
|
4
11
|
|
|
5
|
-
export const useAutoResize = (value: string) => {
|
|
12
|
+
export const useAutoResize = (value: string | undefined) => {
|
|
6
13
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
7
14
|
|
|
8
15
|
useEffect(() => {
|
|
16
|
+
if (value === undefined) return;
|
|
9
17
|
if (!textareaRef.current) return;
|
|
10
18
|
|
|
11
19
|
textareaRef.current.style.height = "auto"; // Reset the height
|
|
@@ -15,29 +23,29 @@ export const useAutoResize = (value: string) => {
|
|
|
15
23
|
return textareaRef;
|
|
16
24
|
};
|
|
17
25
|
|
|
18
|
-
export const
|
|
19
|
-
forwardRef(function
|
|
26
|
+
export const TextArea = memo(
|
|
27
|
+
forwardRef(function TextArea(
|
|
20
28
|
{
|
|
21
29
|
value,
|
|
22
30
|
onChangeText,
|
|
23
31
|
className,
|
|
24
|
-
end,
|
|
25
|
-
endClassName,
|
|
26
32
|
onChange,
|
|
33
|
+
autoResize = false,
|
|
27
34
|
...rest
|
|
28
35
|
}: {
|
|
29
|
-
onChangeText
|
|
36
|
+
onChangeText?: (value: string) => void;
|
|
30
37
|
value?: string;
|
|
31
|
-
|
|
32
|
-
endClassName?: string;
|
|
38
|
+
autoResize?: boolean;
|
|
33
39
|
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
|
34
40
|
forwardedRef: React.ForwardedRef<HTMLTextAreaElement>
|
|
35
41
|
) {
|
|
36
|
-
const
|
|
42
|
+
const autoResizeRef = useAutoResize(
|
|
43
|
+
autoResize ? value || rest.placeholder || "" : undefined
|
|
44
|
+
);
|
|
37
45
|
|
|
38
46
|
const handleChange = useCallback(
|
|
39
47
|
(event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
40
|
-
onChangeText(event.target.value);
|
|
48
|
+
onChangeText?.(event.target.value);
|
|
41
49
|
onChange?.(event);
|
|
42
50
|
},
|
|
43
51
|
[onChangeText, onChange]
|
|
@@ -45,24 +53,53 @@ export const AutoResizingTextArea = memo(
|
|
|
45
53
|
|
|
46
54
|
const handleRef = useCallback(
|
|
47
55
|
(value: HTMLTextAreaElement | null) => {
|
|
48
|
-
|
|
56
|
+
if (autoResize) {
|
|
57
|
+
autoResizeRef.current = value;
|
|
58
|
+
}
|
|
49
59
|
assignRef(forwardedRef, value);
|
|
50
60
|
},
|
|
51
|
-
[
|
|
61
|
+
[autoResize, autoResizeRef, forwardedRef]
|
|
52
62
|
);
|
|
53
63
|
|
|
54
64
|
return (
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
<textarea
|
|
66
|
+
className={cx(
|
|
67
|
+
`font-sans text-heading5 font-normal text-text bg-input-background flex-1 py-1 px-1.5 border-none outline-none min-h-6 w-full rounded resize-none placeholder:text-text-disabled focus:ring-2 focus:ring-primary read-only:text-text-disabled focus:z-interactable transition-all`,
|
|
68
|
+
className
|
|
69
|
+
)}
|
|
70
|
+
ref={handleRef}
|
|
71
|
+
{...rest}
|
|
72
|
+
onChange={handleChange}
|
|
73
|
+
value={value}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
export const TextAreaRow = memo(
|
|
80
|
+
forwardRef(function TextAreaRow(
|
|
81
|
+
{
|
|
82
|
+
className,
|
|
83
|
+
textAreaClassName,
|
|
84
|
+
textAreaRef,
|
|
85
|
+
end,
|
|
86
|
+
endClassName,
|
|
87
|
+
...rest
|
|
88
|
+
}: {
|
|
89
|
+
className?: string;
|
|
90
|
+
textAreaClassName?: string;
|
|
91
|
+
textAreaRef?: React.Ref<HTMLTextAreaElement>;
|
|
92
|
+
end?: React.ReactNode;
|
|
93
|
+
endClassName?: string;
|
|
94
|
+
} & ComponentProps<typeof TextArea>,
|
|
95
|
+
forwardedRef: React.ForwardedRef<HTMLDivElement>
|
|
96
|
+
) {
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
ref={forwardedRef}
|
|
100
|
+
className={cx("relative w-full h-full", className)}
|
|
101
|
+
>
|
|
102
|
+
<TextArea className={textAreaClassName} {...rest} ref={textAreaRef} />
|
|
66
103
|
<div className={cx("absolute right-1 top-4", endClassName)}>{end}</div>
|
|
67
104
|
</div>
|
|
68
105
|
);
|
|
@@ -88,19 +88,20 @@ export function ToolbarMenu<T extends string>({
|
|
|
88
88
|
return (
|
|
89
89
|
<Button
|
|
90
90
|
key={i}
|
|
91
|
+
disabled={item.disabled}
|
|
91
92
|
onClick={() => {
|
|
92
93
|
if (onSelectMenuItem && item.value) {
|
|
93
94
|
onSelectMenuItem(item.value);
|
|
94
95
|
}
|
|
95
96
|
}}
|
|
96
97
|
>
|
|
98
|
+
{item.title}
|
|
97
99
|
{item.icon && (
|
|
98
100
|
<>
|
|
99
|
-
{renderIcon(item.icon)}
|
|
100
101
|
<Spacer.Horizontal inline size={6} />
|
|
102
|
+
{renderIcon(item.icon)}
|
|
101
103
|
</>
|
|
102
104
|
)}
|
|
103
|
-
{item.title}
|
|
104
105
|
</Button>
|
|
105
106
|
);
|
|
106
107
|
}
|
|
@@ -115,13 +116,7 @@ export function ToolbarMenu<T extends string>({
|
|
|
115
116
|
}
|
|
116
117
|
}}
|
|
117
118
|
>
|
|
118
|
-
<Button>
|
|
119
|
-
{item.icon && (
|
|
120
|
-
<>
|
|
121
|
-
{renderIcon(item.icon)}
|
|
122
|
-
<Spacer.Horizontal size={6} />
|
|
123
|
-
</>
|
|
124
|
-
)}
|
|
119
|
+
<Button disabled={item.disabled}>
|
|
125
120
|
{item.title}
|
|
126
121
|
<Spacer.Horizontal size={6} />
|
|
127
122
|
<DropdownChevronIcon />
|