lecom-ui 5.4.44 → 5.4.46
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/dist/components/Accordion/Accordion.js +22 -19
- package/dist/components/Chart/Chart.js +1 -1
- package/dist/components/Combobox/Combobox.js +22 -12
- package/dist/components/CustomTagInput/CustomTagInput.js +107 -33
- package/dist/components/Input/Input.js +9 -4
- package/dist/components/Label/Label.js +39 -3
- package/dist/components/MultiSelect/MultiSelect.js +191 -162
- package/dist/components/Textarea/Textarea.js +9 -5
- package/dist/hooks/useDynamicMaxHeight.js +50 -0
- package/dist/i18n/locales/en_us.js +4 -0
- package/dist/i18n/locales/es_es.js +4 -0
- package/dist/i18n/locales/pt_br.js +4 -0
- package/dist/index.d.ts +34 -15
- package/dist/index.js +2 -1
- package/dist/style.min.css +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
2
3
|
import { cn } from '../../lib/utils.js';
|
|
3
4
|
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
4
5
|
import { cva } from 'class-variance-authority';
|
|
5
6
|
import { ChevronDown } from 'lucide-react';
|
|
7
|
+
import { initializeI18n } from '../../i18n/index.js';
|
|
8
|
+
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '../Tooltip/Tooltip.js';
|
|
9
|
+
import { Typography } from '../Typography/Typography.js';
|
|
6
10
|
|
|
11
|
+
initializeI18n();
|
|
7
12
|
const accordionVariants = cva(
|
|
8
13
|
"flex flex-1 items-center justify-between gap-4 transition-all w-full outline-none",
|
|
9
14
|
{
|
|
@@ -26,6 +31,20 @@ const accordionVariants = cva(
|
|
|
26
31
|
const Accordion = AccordionPrimitive.Root;
|
|
27
32
|
const AccordionItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(AccordionPrimitive.Item, { ref, className: cn(className), ...props }));
|
|
28
33
|
AccordionItem.displayName = "AccordionItem";
|
|
34
|
+
const AccordionIcon = ({ disabled }) => {
|
|
35
|
+
const { t } = useTranslation();
|
|
36
|
+
const icon = /* @__PURE__ */ React.createElement(
|
|
37
|
+
ChevronDown,
|
|
38
|
+
{
|
|
39
|
+
className: cn(
|
|
40
|
+
"size-5 shrink-0 text-grey-800 transition-transform duration-200",
|
|
41
|
+
disabled && "text-grey-300"
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
return /* @__PURE__ */ React.createElement(TooltipProvider, null, /* @__PURE__ */ React.createElement(Tooltip, null, /* @__PURE__ */ React.createElement(TooltipTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(Typography, { className: "inline-flex" }, icon)), /* @__PURE__ */ React.createElement(TooltipContent, { color: "black" }, /* @__PURE__ */ React.createElement(Typography, { className: "[[data-state=open]_&]:hidden" }, t("accordion.expand")), /* @__PURE__ */ React.createElement(Typography, { className: "hidden [[data-state=open]_&]:inline" }, t("accordion.collapse")))));
|
|
46
|
+
};
|
|
47
|
+
AccordionIcon.displayName = "AccordionIcon";
|
|
29
48
|
const AccordionTrigger = React.forwardRef(
|
|
30
49
|
({
|
|
31
50
|
className,
|
|
@@ -43,30 +62,14 @@ const AccordionTrigger = React.forwardRef(
|
|
|
43
62
|
ref,
|
|
44
63
|
className: cn(
|
|
45
64
|
accordionVariants({ variant, size, className }),
|
|
46
|
-
iconDirection === "down-to-up" && "[&[data-state=open]
|
|
47
|
-
iconDirection === "right-to-down" && "[
|
|
65
|
+
iconDirection === "down-to-up" && "[&[data-state=open]_svg]:rotate-180",
|
|
66
|
+
iconDirection === "right-to-down" && "[&_svg]:rotate-[-90deg] [&[data-state=open]_svg]:rotate-0"
|
|
48
67
|
),
|
|
49
68
|
...props,
|
|
50
69
|
disabled,
|
|
51
70
|
asChild
|
|
52
71
|
},
|
|
53
|
-
asChild ? children : /* @__PURE__ */ React.createElement(React.Fragment, null, iconPosition === "left" && /* @__PURE__ */ React.createElement(
|
|
54
|
-
ChevronDown,
|
|
55
|
-
{
|
|
56
|
-
className: cn(
|
|
57
|
-
"size-5 shrink-0 text-grey-800 transition-transform duration-200",
|
|
58
|
-
disabled && "text-grey-300"
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
), children, iconPosition === "right" && /* @__PURE__ */ React.createElement(
|
|
62
|
-
ChevronDown,
|
|
63
|
-
{
|
|
64
|
-
className: cn(
|
|
65
|
-
"size-5 shrink-0 text-grey-800 transition-transform duration-200",
|
|
66
|
-
disabled && "text-grey-300"
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
))
|
|
72
|
+
asChild ? children : /* @__PURE__ */ React.createElement(React.Fragment, null, iconPosition === "left" && /* @__PURE__ */ React.createElement(AccordionIcon, { disabled }), children, iconPosition === "right" && /* @__PURE__ */ React.createElement(AccordionIcon, { disabled }))
|
|
70
73
|
))
|
|
71
74
|
);
|
|
72
75
|
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React__default, { forwardRef, useId, useMemo, useContext } from 'react';
|
|
2
2
|
import { cn } from '../../lib/utils.js';
|
|
3
3
|
import { ResponsiveContainer, Legend, Tooltip } from 'recharts';
|
|
4
|
-
export { Bar, BarChart, CartesianGrid, Label, LabelList, XAxis, YAxis } from 'recharts';
|
|
4
|
+
export { Bar, BarChart, CartesianGrid, Label as ChartLabel, LabelList, XAxis, YAxis } from 'recharts';
|
|
5
5
|
|
|
6
6
|
const THEMES = { light: "", dark: ".dark" };
|
|
7
7
|
const ChartContext = React__default.createContext(null);
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
import { ChevronUpIcon, ChevronDownIcon, Check, Plus } from 'lucide-react';
|
|
5
|
+
import { useDynamicMaxHeight } from '../../hooks/useDynamicMaxHeight.js';
|
|
5
6
|
import { initializeI18n } from '../../i18n/index.js';
|
|
6
7
|
import { cn } from '../../lib/utils.js';
|
|
7
8
|
import { Button } from '../Button/Button.js';
|
|
@@ -309,7 +310,7 @@ const comboboxTriggerVariants = cva(
|
|
|
309
310
|
},
|
|
310
311
|
status: {
|
|
311
312
|
default: "border border-grey-400 hover:border-grey-500 focus:border-grey-400 focus:ring-grey-600 focus:ring-opacity-15 focus:ring-4 outline-none",
|
|
312
|
-
error: "border-
|
|
313
|
+
error: "border border-red-600 hover:border-red-500 focus:border-red-600 focus:ring-0 outline-none"
|
|
313
314
|
},
|
|
314
315
|
disabled: {
|
|
315
316
|
true: "disabled:bg-grey-100 pointer-events-none",
|
|
@@ -409,12 +410,21 @@ function Combobox({
|
|
|
409
410
|
showSearch = true,
|
|
410
411
|
size = "medium",
|
|
411
412
|
allowCreate = false,
|
|
412
|
-
onCreateOption
|
|
413
|
+
onCreateOption,
|
|
414
|
+
dynamicHeight = true,
|
|
415
|
+
dynamicHeightBottomPadding = 50,
|
|
416
|
+
dynamicHeightMinHeight = 120,
|
|
417
|
+
modalPopover = false
|
|
413
418
|
}) {
|
|
414
419
|
const { t } = useTranslation();
|
|
415
420
|
const [open, setOpen] = React.useState(false);
|
|
416
421
|
const [search, setSearch] = React.useState("");
|
|
417
422
|
const commandListRef = React.useRef(null);
|
|
423
|
+
const { ref: dynamicHeightRef, style: dynamicHeightStyle } = useDynamicMaxHeight({
|
|
424
|
+
enabled: open && dynamicHeight,
|
|
425
|
+
bottomPadding: dynamicHeightBottomPadding,
|
|
426
|
+
minHeight: dynamicHeightMinHeight
|
|
427
|
+
});
|
|
418
428
|
const lastOpenOptionsRef = React.useRef(options);
|
|
419
429
|
React.useEffect(() => {
|
|
420
430
|
if (open) {
|
|
@@ -442,7 +452,7 @@ function Combobox({
|
|
|
442
452
|
}
|
|
443
453
|
}, []);
|
|
444
454
|
useComboboxScrollToSelected(open, value, commandListRef);
|
|
445
|
-
return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(
|
|
455
|
+
return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: handleOpenChange, modal: modalPopover }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(
|
|
446
456
|
ComboboxTriggerButton,
|
|
447
457
|
{
|
|
448
458
|
open,
|
|
@@ -458,11 +468,12 @@ function Combobox({
|
|
|
458
468
|
)), /* @__PURE__ */ React.createElement(
|
|
459
469
|
PopoverContent,
|
|
460
470
|
{
|
|
471
|
+
ref: dynamicHeightRef,
|
|
472
|
+
style: dynamicHeightStyle,
|
|
461
473
|
className: cn(
|
|
462
|
-
"w-[var(--radix-popover-trigger-width)] pt-0 px-1 pb-1",
|
|
474
|
+
"w-[var(--radix-popover-trigger-width)] pt-0 px-1 pb-1 flex flex-col z-40",
|
|
463
475
|
contentClassName
|
|
464
|
-
)
|
|
465
|
-
onWheel: (e) => e.stopPropagation()
|
|
476
|
+
)
|
|
466
477
|
},
|
|
467
478
|
/* @__PURE__ */ React.createElement(Command, { shouldFilter: false, className: SEARCH_INPUT_CLASSES[size] }, showSearch && /* @__PURE__ */ React.createElement(
|
|
468
479
|
CommandInput,
|
|
@@ -472,21 +483,20 @@ function Combobox({
|
|
|
472
483
|
onValueChange: setSearch
|
|
473
484
|
}
|
|
474
485
|
), /* @__PURE__ */ React.createElement(
|
|
475
|
-
|
|
486
|
+
CommandList,
|
|
476
487
|
{
|
|
477
488
|
ref: commandListRef,
|
|
478
489
|
key: search,
|
|
479
490
|
className: cn(
|
|
480
|
-
"
|
|
491
|
+
"overflow-y-auto overflow-x-hidden",
|
|
481
492
|
"[&::-webkit-scrollbar]:w-1.5",
|
|
482
493
|
"[&::-webkit-scrollbar-track]:bg-transparent",
|
|
483
494
|
"[&::-webkit-scrollbar-thumb]:bg-grey-300",
|
|
484
495
|
"[&::-webkit-scrollbar-thumb]:rounded-full",
|
|
485
|
-
"[&::-webkit-scrollbar-thumb]:hover:bg-grey-400"
|
|
486
|
-
contentClassName
|
|
496
|
+
"[&::-webkit-scrollbar-thumb]:hover:bg-grey-400"
|
|
487
497
|
)
|
|
488
498
|
},
|
|
489
|
-
/* @__PURE__ */ React.createElement(
|
|
499
|
+
/* @__PURE__ */ React.createElement(
|
|
490
500
|
ComboboxContent,
|
|
491
501
|
{
|
|
492
502
|
showCreateOption,
|
|
@@ -500,7 +510,7 @@ function Combobox({
|
|
|
500
510
|
onChange,
|
|
501
511
|
itemsClassName
|
|
502
512
|
}
|
|
503
|
-
)
|
|
513
|
+
)
|
|
504
514
|
))
|
|
505
515
|
));
|
|
506
516
|
}
|
|
@@ -19,7 +19,8 @@ const CustomTagItemComponent = React.memo(function CustomTagItemComponent2({
|
|
|
19
19
|
isDragging,
|
|
20
20
|
onMouseDown,
|
|
21
21
|
isAllSelected = false,
|
|
22
|
-
defaultColor
|
|
22
|
+
defaultColor,
|
|
23
|
+
maxEditLength
|
|
23
24
|
}) {
|
|
24
25
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
25
26
|
const [editValue, setEditValue] = React.useState(item.label);
|
|
@@ -88,7 +89,13 @@ const CustomTagItemComponent = React.memo(function CustomTagItemComponent2({
|
|
|
88
89
|
ref: inputRef,
|
|
89
90
|
type: "text",
|
|
90
91
|
value: editValue,
|
|
91
|
-
onChange: (e) =>
|
|
92
|
+
onChange: (e) => {
|
|
93
|
+
let newValue = e.target.value;
|
|
94
|
+
if (maxEditLength !== void 0 && newValue.length > maxEditLength) {
|
|
95
|
+
newValue = newValue.slice(0, maxEditLength);
|
|
96
|
+
}
|
|
97
|
+
setEditValue(newValue);
|
|
98
|
+
},
|
|
92
99
|
onKeyDown: handleKeyDown,
|
|
93
100
|
onBlur: handleBlur,
|
|
94
101
|
className: "bg-transparent border-none outline-none [color:inherit] body-small-400 min-w-[60px] w-full",
|
|
@@ -169,18 +176,22 @@ const TagItemWrapper = React.memo(function TagItemWrapper2({
|
|
|
169
176
|
onSpacerClick,
|
|
170
177
|
onMouseDown,
|
|
171
178
|
isAllSelected = false,
|
|
172
|
-
defaultColor
|
|
179
|
+
defaultColor,
|
|
180
|
+
maxEditLength,
|
|
181
|
+
remainingCharacters
|
|
173
182
|
}) {
|
|
174
183
|
const showInlineInput = insertAtIndex === index;
|
|
175
184
|
const showDragIndicator = dragOverIndex === index && draggedIndex !== null && draggedIndex !== index;
|
|
176
|
-
const
|
|
185
|
+
const isMaxLengthReached = remainingCharacters !== void 0 && remainingCharacters <= 0;
|
|
186
|
+
const showSpacer = !readOnly && insertAtIndex !== index + 1 && !isMaxLengthReached;
|
|
177
187
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, showInlineInput && /* @__PURE__ */ React.createElement(
|
|
178
188
|
InlineInput,
|
|
179
189
|
{
|
|
180
190
|
onAdd: onInlineAdd,
|
|
181
191
|
onCancel: onInlineCancel,
|
|
182
192
|
placeholder: inlinePlaceholder,
|
|
183
|
-
color: defaultColor
|
|
193
|
+
color: defaultColor,
|
|
194
|
+
maxLength: remainingCharacters
|
|
184
195
|
}
|
|
185
196
|
), /* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-0.5 relative" }, /* @__PURE__ */ React.createElement(
|
|
186
197
|
CustomTagItemComponent,
|
|
@@ -198,7 +209,8 @@ const TagItemWrapper = React.memo(function TagItemWrapper2({
|
|
|
198
209
|
isDragging: draggedIndex === index,
|
|
199
210
|
onMouseDown,
|
|
200
211
|
isAllSelected,
|
|
201
|
-
defaultColor
|
|
212
|
+
defaultColor,
|
|
213
|
+
maxEditLength
|
|
202
214
|
}
|
|
203
215
|
), showDragIndicator && /* @__PURE__ */ React.createElement("div", { className: "w-1 h-6 bg-blue-500 rounded-full animate-pulse self-center" }), showSpacer && /* @__PURE__ */ React.createElement(
|
|
204
216
|
"div",
|
|
@@ -212,7 +224,7 @@ const TagItemWrapper = React.memo(function TagItemWrapper2({
|
|
|
212
224
|
}
|
|
213
225
|
)));
|
|
214
226
|
});
|
|
215
|
-
const InlineInput = React.memo(function InlineInput2({ onAdd, onCancel, placeholder, color }) {
|
|
227
|
+
const InlineInput = React.memo(function InlineInput2({ onAdd, onCancel, placeholder, color, maxLength }) {
|
|
216
228
|
const [value, setValue] = React.useState("");
|
|
217
229
|
const inputRef = React.useRef(null);
|
|
218
230
|
React.useEffect(() => {
|
|
@@ -247,7 +259,13 @@ const InlineInput = React.memo(function InlineInput2({ onAdd, onCancel, placehol
|
|
|
247
259
|
ref: inputRef,
|
|
248
260
|
type: "text",
|
|
249
261
|
value,
|
|
250
|
-
onChange: (e) =>
|
|
262
|
+
onChange: (e) => {
|
|
263
|
+
let newValue = e.target.value;
|
|
264
|
+
if (maxLength !== void 0 && newValue.length > maxLength) {
|
|
265
|
+
newValue = newValue.slice(0, maxLength);
|
|
266
|
+
}
|
|
267
|
+
setValue(newValue);
|
|
268
|
+
},
|
|
251
269
|
onKeyDown: handleKeyDown,
|
|
252
270
|
onBlur: handleBlur,
|
|
253
271
|
placeholder,
|
|
@@ -257,7 +275,8 @@ const InlineInput = React.memo(function InlineInput2({ onAdd, onCancel, placehol
|
|
|
257
275
|
}
|
|
258
276
|
));
|
|
259
277
|
});
|
|
260
|
-
function useTagManagement(value, onChange, allowDuplicates) {
|
|
278
|
+
function useTagManagement(value, onChange, allowDuplicates, maxLength) {
|
|
279
|
+
const getTotalCharacters = React.useCallback(() => value.reduce((total, item) => total + item.label.length, 0), [value]);
|
|
261
280
|
const isDuplicateTag = React.useCallback(
|
|
262
281
|
(label) => value.some(
|
|
263
282
|
(item) => item.label.toLowerCase() === label.toLowerCase()
|
|
@@ -287,28 +306,39 @@ function useTagManagement(value, onChange, allowDuplicates) {
|
|
|
287
306
|
(newLabel, atIndex) => {
|
|
288
307
|
const trimmedValue = newLabel.trim();
|
|
289
308
|
if (!trimmedValue) return;
|
|
309
|
+
if (maxLength !== void 0) {
|
|
310
|
+
const currentTotal = getTotalCharacters();
|
|
311
|
+
if (currentTotal + trimmedValue.length > maxLength) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
290
315
|
if (!allowDuplicates && isDuplicateTag(trimmedValue)) {
|
|
291
316
|
return;
|
|
292
317
|
}
|
|
293
318
|
const newItem = createTagItem(trimmedValue);
|
|
294
319
|
addTagAtPosition(newItem, atIndex);
|
|
295
320
|
},
|
|
296
|
-
[allowDuplicates, isDuplicateTag, addTagAtPosition, createTagItem]
|
|
321
|
+
[allowDuplicates, isDuplicateTag, addTagAtPosition, createTagItem, maxLength, getTotalCharacters]
|
|
297
322
|
);
|
|
298
323
|
const handleAddMultipleTags = React.useCallback(
|
|
299
324
|
(labels) => {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
325
|
+
let currentTotal = getTotalCharacters();
|
|
326
|
+
const newItems = [];
|
|
327
|
+
for (const label of labels) {
|
|
328
|
+
const trimmed = label.trim();
|
|
329
|
+
if (!trimmed) continue;
|
|
330
|
+
if (!allowDuplicates && isDuplicateTag(trimmed)) continue;
|
|
331
|
+
if (maxLength !== void 0 && currentTotal + trimmed.length > maxLength) {
|
|
332
|
+
break;
|
|
304
333
|
}
|
|
305
|
-
|
|
306
|
-
|
|
334
|
+
newItems.push(createTagItem(trimmed));
|
|
335
|
+
currentTotal += trimmed.length;
|
|
336
|
+
}
|
|
307
337
|
if (newItems.length > 0) {
|
|
308
338
|
onChange([...value, ...newItems]);
|
|
309
339
|
}
|
|
310
340
|
},
|
|
311
|
-
[value, onChange, allowDuplicates, isDuplicateTag, createTagItem]
|
|
341
|
+
[value, onChange, allowDuplicates, isDuplicateTag, createTagItem, maxLength, getTotalCharacters]
|
|
312
342
|
);
|
|
313
343
|
const handleRemove = React.useCallback(
|
|
314
344
|
(id) => {
|
|
@@ -431,7 +461,7 @@ function useDragAndDrop(value, onChange, containerRef) {
|
|
|
431
461
|
handleMouseDown
|
|
432
462
|
};
|
|
433
463
|
}
|
|
434
|
-
function useInlineInputHandlers(insertAtIndex, setInsertAtIndex, handleAddTag, readOnly, disabled) {
|
|
464
|
+
function useInlineInputHandlers(insertAtIndex, setInsertAtIndex, handleAddTag, readOnly, disabled, isMaxLengthReached) {
|
|
435
465
|
const handleInlineAdd = React.useCallback(
|
|
436
466
|
(newLabel) => {
|
|
437
467
|
if (insertAtIndex !== null) {
|
|
@@ -446,12 +476,12 @@ function useInlineInputHandlers(insertAtIndex, setInsertAtIndex, handleAddTag, r
|
|
|
446
476
|
}, [setInsertAtIndex]);
|
|
447
477
|
const handleSpacerClick = React.useCallback(
|
|
448
478
|
(index) => {
|
|
449
|
-
const canInsert = !readOnly && !disabled;
|
|
479
|
+
const canInsert = !readOnly && !disabled && !isMaxLengthReached;
|
|
450
480
|
if (canInsert) {
|
|
451
481
|
setInsertAtIndex(index);
|
|
452
482
|
}
|
|
453
483
|
},
|
|
454
|
-
[readOnly, disabled, setInsertAtIndex]
|
|
484
|
+
[readOnly, disabled, isMaxLengthReached, setInsertAtIndex]
|
|
455
485
|
);
|
|
456
486
|
return { handleInlineAdd, handleInlineCancel, handleSpacerClick };
|
|
457
487
|
}
|
|
@@ -567,9 +597,19 @@ function useInputHandlers(inputValue, setInputValue, value, onChange, handleAddT
|
|
|
567
597
|
);
|
|
568
598
|
return { handleKeyDown, handlePaste };
|
|
569
599
|
}
|
|
570
|
-
function useTagEditHandler(value, onChange, onTagEdit) {
|
|
600
|
+
function useTagEditHandler(value, onChange, onTagEdit, maxLength) {
|
|
571
601
|
const handleEdit = React.useCallback(
|
|
572
602
|
(id, newLabel) => {
|
|
603
|
+
if (maxLength !== void 0) {
|
|
604
|
+
value.find((item) => item.id === id);
|
|
605
|
+
const otherItemsTotal = value.reduce(
|
|
606
|
+
(total, item) => total + (item.id !== id ? item.label.length : 0),
|
|
607
|
+
0
|
|
608
|
+
);
|
|
609
|
+
if (otherItemsTotal + newLabel.length > maxLength) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
573
613
|
const updatedItems = value.map(
|
|
574
614
|
(item) => item.id === id ? { ...item, label: newLabel } : item
|
|
575
615
|
);
|
|
@@ -579,7 +619,7 @@ function useTagEditHandler(value, onChange, onTagEdit) {
|
|
|
579
619
|
onTagEdit(editedItem);
|
|
580
620
|
}
|
|
581
621
|
},
|
|
582
|
-
[value, onChange, onTagEdit]
|
|
622
|
+
[value, onChange, onTagEdit, maxLength]
|
|
583
623
|
);
|
|
584
624
|
return { handleEdit };
|
|
585
625
|
}
|
|
@@ -643,12 +683,17 @@ function useContainerKeyHandler(containerRef, value, onChange, inputRef, setInpu
|
|
|
643
683
|
);
|
|
644
684
|
return { handleContainerKeyDown };
|
|
645
685
|
}
|
|
646
|
-
|
|
686
|
+
const STATUS_STYLES = {
|
|
687
|
+
default: "",
|
|
688
|
+
error: "border-red-600 hover:border-red-600 focus:border-red-600 focus-within:border-red-600 focus:ring-0"
|
|
689
|
+
};
|
|
690
|
+
function useContainerStyles(variant, radius, disabled, className, maxHeight, status = "default") {
|
|
647
691
|
const textareaRadius = radius === "full" ? "large" : radius;
|
|
648
692
|
const containerClassNames = cn(
|
|
649
693
|
textareaVariants({ variant, radius: textareaRadius }),
|
|
650
694
|
"min-h-10 cursor-text overflow-hidden pr-0.5 py-1",
|
|
651
695
|
disabled && "opacity-50 pointer-events-none cursor-not-allowed",
|
|
696
|
+
STATUS_STYLES[status],
|
|
652
697
|
className
|
|
653
698
|
);
|
|
654
699
|
const containerStyles = React.useMemo(
|
|
@@ -685,7 +730,9 @@ function CustomTagInputRenderer({
|
|
|
685
730
|
handleMouseDown,
|
|
686
731
|
isAllSelected,
|
|
687
732
|
setIsAllSelected,
|
|
688
|
-
defaultColor
|
|
733
|
+
defaultColor,
|
|
734
|
+
isMaxLengthReached,
|
|
735
|
+
remainingCharacters
|
|
689
736
|
}) {
|
|
690
737
|
const showFinalInlineInput = insertAtIndex === value.length;
|
|
691
738
|
const inputPlaceholder = value.length === 0 ? placeholder : "";
|
|
@@ -712,7 +759,9 @@ function CustomTagInputRenderer({
|
|
|
712
759
|
onSpacerClick: handleSpacerClick,
|
|
713
760
|
onMouseDown: handleMouseDown,
|
|
714
761
|
isAllSelected,
|
|
715
|
-
defaultColor
|
|
762
|
+
defaultColor,
|
|
763
|
+
maxEditLength: remainingCharacters !== void 0 ? remainingCharacters + item.label.length : void 0,
|
|
764
|
+
remainingCharacters
|
|
716
765
|
}
|
|
717
766
|
)), showFinalInlineInput && /* @__PURE__ */ React.createElement(
|
|
718
767
|
InlineInput,
|
|
@@ -720,17 +769,29 @@ function CustomTagInputRenderer({
|
|
|
720
769
|
onAdd: handleInlineAdd,
|
|
721
770
|
onCancel: handleInlineCancel,
|
|
722
771
|
placeholder: inlinePlaceholder,
|
|
723
|
-
color: defaultColor
|
|
772
|
+
color: defaultColor,
|
|
773
|
+
maxLength: remainingCharacters
|
|
724
774
|
}
|
|
725
775
|
), !readOnly && /* @__PURE__ */ React.createElement(
|
|
726
776
|
"span",
|
|
727
777
|
{
|
|
728
778
|
ref: inputRef,
|
|
729
|
-
contentEditable: !disabled,
|
|
779
|
+
contentEditable: !disabled && !isMaxLengthReached,
|
|
730
780
|
suppressContentEditableWarning: true,
|
|
731
781
|
onInput: (e) => {
|
|
732
782
|
const target = e.target;
|
|
733
|
-
|
|
783
|
+
let content = target.textContent || "";
|
|
784
|
+
if (remainingCharacters !== void 0 && content.length > remainingCharacters) {
|
|
785
|
+
content = content.slice(0, remainingCharacters);
|
|
786
|
+
target.textContent = content;
|
|
787
|
+
const range = document.createRange();
|
|
788
|
+
const selection = window.getSelection();
|
|
789
|
+
range.selectNodeContents(target);
|
|
790
|
+
range.collapse(false);
|
|
791
|
+
selection?.removeAllRanges();
|
|
792
|
+
selection?.addRange(range);
|
|
793
|
+
}
|
|
794
|
+
setInputValue(content);
|
|
734
795
|
},
|
|
735
796
|
onKeyDown: handleKeyDown,
|
|
736
797
|
onPaste: handlePaste,
|
|
@@ -757,6 +818,8 @@ function CustomTagInput(props) {
|
|
|
757
818
|
enableReorder = true,
|
|
758
819
|
onTagEdit,
|
|
759
820
|
color = "blue",
|
|
821
|
+
maxLength,
|
|
822
|
+
status = "default",
|
|
760
823
|
...restProps
|
|
761
824
|
} = props;
|
|
762
825
|
const [inputValue, setInputValue] = React.useState("");
|
|
@@ -768,7 +831,8 @@ function CustomTagInput(props) {
|
|
|
768
831
|
const { handleAddTag, handleAddMultipleTags, handleRemove } = useTagManagement(
|
|
769
832
|
value,
|
|
770
833
|
onChange,
|
|
771
|
-
allowDuplicates
|
|
834
|
+
allowDuplicates,
|
|
835
|
+
maxLength
|
|
772
836
|
);
|
|
773
837
|
const { draggedIndex, dragOverIndex, handleDragStart, handleDragOver, handleDrag, handleDragEnd, handleMouseDown } = useDragAndDrop(value, onChange, containerRef);
|
|
774
838
|
const { handleKeyDown, handlePaste } = useInputHandlers(
|
|
@@ -783,7 +847,7 @@ function CustomTagInput(props) {
|
|
|
783
847
|
setIsAllSelected,
|
|
784
848
|
isAllSelected
|
|
785
849
|
);
|
|
786
|
-
const { handleEdit } = useTagEditHandler(value, onChange, onTagEdit);
|
|
850
|
+
const { handleEdit } = useTagEditHandler(value, onChange, onTagEdit, maxLength);
|
|
787
851
|
const { handleContainerClick } = useContainerClickHandler(disabled, inputRef, setIsAllSelected);
|
|
788
852
|
const { handleContainerKeyDown } = useContainerKeyHandler(
|
|
789
853
|
containerRef,
|
|
@@ -795,19 +859,27 @@ function CustomTagInput(props) {
|
|
|
795
859
|
setIsAllSelected,
|
|
796
860
|
isAllSelected
|
|
797
861
|
);
|
|
862
|
+
const totalCharacters = React.useMemo(
|
|
863
|
+
() => value.reduce((total, item) => total + item.label.length, 0),
|
|
864
|
+
[value]
|
|
865
|
+
);
|
|
866
|
+
const isMaxLengthReached = maxLength !== void 0 && totalCharacters >= maxLength;
|
|
867
|
+
const remainingCharacters = maxLength !== void 0 ? Math.max(0, maxLength - totalCharacters) : void 0;
|
|
798
868
|
const { handleInlineAdd, handleInlineCancel, handleSpacerClick } = useInlineInputHandlers(
|
|
799
869
|
insertAtIndex,
|
|
800
870
|
setInsertAtIndex,
|
|
801
871
|
handleAddTag,
|
|
802
872
|
readOnly,
|
|
803
|
-
disabled
|
|
873
|
+
disabled,
|
|
874
|
+
isMaxLengthReached
|
|
804
875
|
);
|
|
805
876
|
const { containerClassNames, containerStyles } = useContainerStyles(
|
|
806
877
|
variant,
|
|
807
878
|
radius,
|
|
808
879
|
disabled,
|
|
809
880
|
className,
|
|
810
|
-
maxHeight
|
|
881
|
+
maxHeight,
|
|
882
|
+
status
|
|
811
883
|
);
|
|
812
884
|
return /* @__PURE__ */ React.createElement(
|
|
813
885
|
"div",
|
|
@@ -858,7 +930,9 @@ function CustomTagInput(props) {
|
|
|
858
930
|
handleMouseDown,
|
|
859
931
|
isAllSelected,
|
|
860
932
|
setIsAllSelected,
|
|
861
|
-
defaultColor: color
|
|
933
|
+
defaultColor: color,
|
|
934
|
+
isMaxLengthReached,
|
|
935
|
+
remainingCharacters
|
|
862
936
|
}
|
|
863
937
|
)
|
|
864
938
|
)
|
|
@@ -3,9 +3,8 @@ import { cn } from '../../lib/utils.js';
|
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
const inputVariants = cva(
|
|
6
|
-
`flex w-full rounded-sm border
|
|
6
|
+
`flex w-full rounded-sm border bg-background px-3 py-2
|
|
7
7
|
placeholder:text-grey-500 outline-none
|
|
8
|
-
hover:border-grey-500 focus:bg-background focus:border-grey-400 focus:ring-grey-600 focus:ring-opacity-15 focus:ring-4
|
|
9
8
|
disabled:cursor-not-allowed disabled:bg-grey-100 disabled:border-grey-400
|
|
10
9
|
transition-all duration-300`,
|
|
11
10
|
{
|
|
@@ -25,12 +24,17 @@ const inputVariants = cva(
|
|
|
25
24
|
default: "rounded-sm",
|
|
26
25
|
large: "rounded-3xl",
|
|
27
26
|
full: "rounded-full"
|
|
27
|
+
},
|
|
28
|
+
status: {
|
|
29
|
+
default: "border-grey-400 hover:border-grey-500 focus:bg-background focus:border-grey-400 focus:ring-grey-600 focus:ring-opacity-15 focus:ring-4",
|
|
30
|
+
error: "border-red-600 hover:border-red-600 focus:border-red-600 focus:ring-0"
|
|
28
31
|
}
|
|
29
32
|
},
|
|
30
33
|
defaultVariants: {
|
|
31
34
|
size: "default",
|
|
32
35
|
variant: "default",
|
|
33
|
-
radius: "default"
|
|
36
|
+
radius: "default",
|
|
37
|
+
status: "default"
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
);
|
|
@@ -48,6 +52,7 @@ const Input = React.forwardRef(
|
|
|
48
52
|
sufix,
|
|
49
53
|
prefix,
|
|
50
54
|
radius,
|
|
55
|
+
status,
|
|
51
56
|
iconBefore,
|
|
52
57
|
iconAfter,
|
|
53
58
|
type,
|
|
@@ -57,7 +62,7 @@ const Input = React.forwardRef(
|
|
|
57
62
|
...props
|
|
58
63
|
}, ref) => {
|
|
59
64
|
const inputStyles = () => cn(
|
|
60
|
-
inputVariants({ size, variant, radius }),
|
|
65
|
+
inputVariants({ size, variant, radius, status }),
|
|
61
66
|
prefix && "rounded-l-none",
|
|
62
67
|
sufix && "rounded-r-none",
|
|
63
68
|
iconBefore && "pl-10",
|
|
@@ -4,13 +4,49 @@ import * as LabelPrimitive from '@radix-ui/react-label';
|
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
const labelVariants = cva(
|
|
7
|
-
"
|
|
7
|
+
"leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
"heading-xxlarge-500": "heading-xxlarge-500",
|
|
12
|
+
"heading-xlarge-500": "heading-xlarge-500",
|
|
13
|
+
"heading-large-600": "heading-large-600",
|
|
14
|
+
"heading-large-500": "heading-large-500",
|
|
15
|
+
"heading-medium-600": "heading-medium-600",
|
|
16
|
+
"heading-medium-500": "heading-medium-500",
|
|
17
|
+
"heading-small-600": "heading-small-600",
|
|
18
|
+
"heading-small-500": "heading-small-500",
|
|
19
|
+
"heading-xsmall-600": "heading-xsmall-600",
|
|
20
|
+
"heading-xsmall-500": "heading-xsmall-500",
|
|
21
|
+
"heading-xxsmall-600": "heading-xxsmall-600",
|
|
22
|
+
"heading-xxsmall-500": "heading-xxsmall-500",
|
|
23
|
+
"body-large-700": "body-large-700",
|
|
24
|
+
"body-large-500": "body-large-500",
|
|
25
|
+
"body-large-400": "body-large-400",
|
|
26
|
+
"body-medium-700": "body-medium-700",
|
|
27
|
+
"body-medium-500": "body-medium-500",
|
|
28
|
+
"body-medium-400": "body-medium-400",
|
|
29
|
+
"body-small-700": "body-small-700",
|
|
30
|
+
"body-small-500": "body-small-500",
|
|
31
|
+
"body-small-400": "body-small-400",
|
|
32
|
+
"code-medium-400": "code-medium-400"
|
|
33
|
+
},
|
|
34
|
+
status: {
|
|
35
|
+
default: "",
|
|
36
|
+
error: "text-red-600"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
defaultVariants: {
|
|
40
|
+
variant: "body-medium-400",
|
|
41
|
+
status: "default"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
8
44
|
);
|
|
9
|
-
const Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
45
|
+
const Label = React.forwardRef(({ className, variant, status, ...props }, ref) => /* @__PURE__ */ React.createElement(
|
|
10
46
|
LabelPrimitive.Root,
|
|
11
47
|
{
|
|
12
48
|
ref,
|
|
13
|
-
className: cn(labelVariants(), className),
|
|
49
|
+
className: cn(labelVariants({ variant, status }), className),
|
|
14
50
|
...props
|
|
15
51
|
}
|
|
16
52
|
));
|