@firecms/ui 3.0.0-beta.11 → 3.0.0-beta.13

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.
Files changed (37) hide show
  1. package/dist/components/Avatar.d.ts +1 -0
  2. package/dist/components/BooleanSwitch.d.ts +1 -1
  3. package/dist/components/BooleanSwitchWithLabel.d.ts +1 -1
  4. package/dist/components/Button.d.ts +6 -4
  5. package/dist/components/CircularProgress.d.ts +1 -1
  6. package/dist/components/DateTimeField.d.ts +1 -1
  7. package/dist/components/Dialog.d.ts +2 -1
  8. package/dist/components/Menu.d.ts +4 -1
  9. package/dist/components/MultiSelect.d.ts +14 -22
  10. package/dist/components/Select.d.ts +10 -9
  11. package/dist/components/Sheet.d.ts +2 -0
  12. package/dist/components/TextField.d.ts +38 -3
  13. package/dist/index.es.js +788 -684
  14. package/dist/index.es.js.map +1 -1
  15. package/dist/index.umd.js +788 -684
  16. package/dist/index.umd.js.map +1 -1
  17. package/package.json +30 -29
  18. package/src/components/Avatar.tsx +4 -1
  19. package/src/components/BooleanSwitch.tsx +1 -1
  20. package/src/components/BooleanSwitchWithLabel.tsx +7 -2
  21. package/src/components/Button.tsx +16 -17
  22. package/src/components/Chip.tsx +1 -0
  23. package/src/components/CircularProgress.tsx +7 -3
  24. package/src/components/DateTimeField.tsx +29 -23
  25. package/src/components/Dialog.tsx +3 -1
  26. package/src/components/DialogContent.tsx +1 -1
  27. package/src/components/FileUpload.tsx +2 -1
  28. package/src/components/Menu.tsx +13 -4
  29. package/src/components/Menubar.tsx +1 -1
  30. package/src/components/MultiSelect.tsx +54 -51
  31. package/src/components/SearchBar.tsx +1 -1
  32. package/src/components/Select.tsx +70 -55
  33. package/src/components/Sheet.tsx +9 -1
  34. package/src/components/Tabs.tsx +3 -1
  35. package/src/components/TextField.tsx +190 -153
  36. package/src/components/TextareaAutosize.tsx +2 -2
  37. package/src/components/Tooltip.tsx +0 -1
@@ -18,41 +18,33 @@ import {
18
18
  } from "../styles";
19
19
  import { useInjectStyles } from "../hooks";
20
20
 
21
- interface MultiSelectContextProps {
22
- fieldValue?: string[];
23
- onItemClick: (v: string) => void;
21
+ export type MultiSelectValue = string | number | boolean;
22
+
23
+ // Make the context properly generic
24
+ interface MultiSelectContextProps<T extends MultiSelectValue = string> {
25
+ fieldValue?: T[];
26
+ onItemClick: (v: T) => void;
24
27
  }
25
28
 
26
- export const MultiSelectContext = React.createContext<MultiSelectContextProps>({} as any);
29
+ // Create a proper generic context
30
+ export const MultiSelectContext = React.createContext<MultiSelectContextProps<any>>({} as any);
27
31
 
28
32
  /**
29
33
  * Props for MultiSelect component
30
34
  */
31
- interface MultiSelectProps {
32
-
33
- /**
34
- * The modality of the popover. When set to true, interaction with outside elements
35
- * will be disabled and only popover content will be visible to screen readers.
36
- * Optional, defaults to false.
37
- */
35
+ interface MultiSelectProps<T extends MultiSelectValue = string> {
38
36
  modalPopover?: boolean;
39
-
40
- /**
41
- * Additional class names to apply custom styles to the multi-select component.
42
- * Optional, can be used to add custom styles.
43
- */
44
37
  className?: string;
45
-
46
38
  open?: boolean,
47
39
  name?: string,
48
40
  id?: string,
49
41
  onOpenChange?: (open: boolean) => void,
50
- value?: string[],
42
+ value?: T[],
51
43
  inputClassName?: string,
52
44
  onChange?: React.EventHandler<ChangeEvent<HTMLSelectElement>>,
53
- onValueChange?: (updatedValue: string[]) => void,
45
+ onValueChange?: (updatedValue: T[]) => void,
54
46
  placeholder?: React.ReactNode,
55
- size?: "small" | "medium",
47
+ size?: "smallest" | "small" | "medium" | "large",
56
48
  useChips?: boolean,
57
49
  label?: React.ReactNode | string,
58
50
  disabled?: boolean,
@@ -66,9 +58,10 @@ interface MultiSelectProps {
66
58
  padding?: boolean,
67
59
  invisible?: boolean,
68
60
  children: React.ReactNode;
69
- renderValues?: (values: string[]) => React.ReactNode;
61
+ renderValues?: (values: T[]) => React.ReactNode;
70
62
  }
71
63
 
64
+ // Use generic type for the forwarded ref
72
65
  export const MultiSelect = React.forwardRef<
73
66
  HTMLButtonElement,
74
67
  MultiSelectProps
@@ -76,7 +69,7 @@ export const MultiSelect = React.forwardRef<
76
69
  (
77
70
  {
78
71
  value,
79
- size,
72
+ size = "large",
80
73
  label,
81
74
  error,
82
75
  onValueChange,
@@ -95,8 +88,9 @@ export const MultiSelect = React.forwardRef<
95
88
  },
96
89
  ref
97
90
  ) => {
91
+ // Properly type the state variables to match the generic props
98
92
  const [isPopoverOpen, setIsPopoverOpen] = React.useState(open ?? false);
99
- const [selectedValues, setSelectedValues] = React.useState<string[]>(value ?? []);
93
+ const [selectedValues, setSelectedValues] = React.useState<any[]>(value ?? []);
100
94
 
101
95
  const onPopoverOpenChange = (open: boolean) => {
102
96
  setIsPopoverOpen(open);
@@ -115,24 +109,24 @@ export const MultiSelect = React.forwardRef<
115
109
  return child.props.value;
116
110
  }
117
111
  return null;
118
- }).filter(Boolean) as string[]
112
+ }).filter(Boolean) as any[]
119
113
  : [];
120
114
 
121
115
  React.useEffect(() => {
122
116
  setSelectedValues(value ?? []);
123
117
  }, [value]);
124
118
 
125
- function onItemClick(newValue: string) {
126
- let newSelectedValues: string[];
127
- if (selectedValues.includes(newValue)) {
128
- newSelectedValues = selectedValues.filter((v) => v !== newValue);
119
+ function onItemClick(newValue: any) {
120
+ let newSelectedValues: any[];
121
+ if (selectedValues.some(v => String(v) === String(newValue))) {
122
+ newSelectedValues = selectedValues.filter(v => String(v) !== String(newValue));
129
123
  } else {
130
124
  newSelectedValues = [...selectedValues, newValue];
131
125
  }
132
126
  updateValues(newSelectedValues);
133
127
  }
134
128
 
135
- function updateValues(values: string[]) {
129
+ function updateValues(values: any[]) {
136
130
  setSelectedValues(values);
137
131
  onValueChange?.(values);
138
132
  }
@@ -149,9 +143,9 @@ export const MultiSelect = React.forwardRef<
149
143
  }
150
144
  };
151
145
 
152
- const toggleOption = (value: string) => {
153
- const newSelectedValues = selectedValues.includes(value)
154
- ? selectedValues.filter((v) => v !== value)
146
+ const toggleOption = (value: any) => {
147
+ const newSelectedValues = selectedValues.some(v => String(v) === String(value))
148
+ ? selectedValues.filter(v => String(v) !== String(value))
155
149
  : [...selectedValues, value];
156
150
  updateValues(newSelectedValues);
157
151
  };
@@ -199,9 +193,20 @@ export const MultiSelect = React.forwardRef<
199
193
  ref={ref}
200
194
  onClick={handleTogglePopover}
201
195
  className={cls(
202
- size === "small" ? "min-h-[42px]" : "min-h-[64px]",
203
- "py-2",
204
- "px-4",
196
+ {
197
+ "min-h-[28px]": size === "smallest",
198
+ "min-h-[32px]": size === "small",
199
+ "min-h-[42px]": size === "medium",
200
+ "min-h-[64px]": size === "large",
201
+ },
202
+ {
203
+ "py-1": size === "small" || size === "smallest",
204
+ "py-2": size === "medium" || size === "large",
205
+ },
206
+ {
207
+ "px-2": size === "small" || size === "smallest",
208
+ "px-4": size === "medium" || size === "large",
209
+ },
205
210
  "select-none rounded-md text-sm",
206
211
  invisible ? fieldBackgroundInvisibleMixin : fieldBackgroundMixin,
207
212
  disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
@@ -222,14 +227,14 @@ export const MultiSelect = React.forwardRef<
222
227
  }
223
228
  }).filter(Boolean);
224
229
 
225
- const option = childrenProps.find((o) => o.value === value);
230
+ const option = childrenProps.find((o) => String(o.value) === String(value));
226
231
  if (!useChips) {
227
232
  return option?.children;
228
233
  }
229
234
  return (
230
235
  <Chip
231
236
  size={"medium"}
232
- key={value}
237
+ key={String(value)}
233
238
  className={cls("flex flex-row items-center p-1")}
234
239
  >
235
240
  {option?.children}
@@ -255,7 +260,7 @@ export const MultiSelect = React.forwardRef<
255
260
  />}
256
261
  <div className={cls("px-2 h-full flex items-center")}>
257
262
  <KeyboardArrowDownIcon size={"small"}
258
- className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
263
+ className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
259
264
  </div>
260
265
  </div>
261
266
  </div>
@@ -266,7 +271,7 @@ export const MultiSelect = React.forwardRef<
266
271
  </span>
267
272
  <div className={cls("px-2 h-full flex items-center")}>
268
273
  <KeyboardArrowDownIcon size={"small"}
269
- className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
274
+ className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
270
275
  </div>
271
276
  </div>
272
277
  )}
@@ -319,7 +324,6 @@ export const MultiSelect = React.forwardRef<
319
324
  </CommandPrimitive.Item>}
320
325
  {children}
321
326
  </CommandPrimitive.Group>
322
-
323
327
  </CommandPrimitive.List>
324
328
  </CommandPrimitive>
325
329
  </PopoverPrimitive.Content>
@@ -331,18 +335,17 @@ export const MultiSelect = React.forwardRef<
331
335
 
332
336
  MultiSelect.displayName = "MultiSelect";
333
337
 
334
- export interface MultiSelectItemProps {
335
- value: string;
338
+ export interface MultiSelectItemProps<T extends MultiSelectValue = string> {
339
+ value: T;
336
340
  children?: React.ReactNode,
337
341
  className?: string;
338
342
  }
339
343
 
340
- export function MultiSelectItem({
341
- children,
342
- value,
343
- className
344
- }: MultiSelectItemProps) {
345
-
344
+ export function MultiSelectItem<T extends MultiSelectValue = string>({
345
+ children,
346
+ value,
347
+ className
348
+ }: MultiSelectItemProps<T>) {
346
349
  const context = React.useContext(MultiSelectContext);
347
350
  if (!context) throw new Error("MultiSelectItem must be used inside a MultiSelect");
348
351
  const {
@@ -350,9 +353,9 @@ export function MultiSelectItem({
350
353
  onItemClick
351
354
  } = context;
352
355
 
353
- const isSelected = (fieldValue ?? []).includes(value);
356
+ const isSelected = (fieldValue ?? []).some(v => String(v) === String(value));
357
+
354
358
  return <CommandPrimitive.Item
355
- // value={value}
356
359
  onMouseDown={(e) => {
357
360
  e.preventDefault();
358
361
  e.stopPropagation();
@@ -375,9 +378,9 @@ export function MultiSelectItem({
375
378
  <InnerCheckBox checked={isSelected}/>
376
379
  {children}
377
380
  </CommandPrimitive.Item>;
378
-
379
381
  }
380
382
 
383
+
381
384
  function InnerCheckBox({ checked }: { checked: boolean }) {
382
385
  return <div className={cls(
383
386
  "p-2",
@@ -69,7 +69,7 @@ export function SearchBar({
69
69
  className)}>
70
70
  <div
71
71
  className="absolute p-0 px-4 h-full pointer-events-none flex items-center justify-center top-0">
72
- {loading ? <CircularProgress size={"small"}/> : <SearchIcon className={"text-text-disabled dark:text-text-disabled-dark"}/>}
72
+ {loading ? <CircularProgress size={"smallest"}/> : <SearchIcon className={"text-text-disabled dark:text-text-disabled-dark"}/>}
73
73
  </div>
74
74
  <input
75
75
  value={searchText ?? ""}
@@ -13,20 +13,22 @@ import { CheckIcon, KeyboardArrowDownIcon } from "../icons";
13
13
  import { cls } from "../util";
14
14
  import { SelectInputLabel } from "./common/SelectInputLabel";
15
15
 
16
- export type SelectProps = {
16
+ export type SelectValue = string | number | boolean;
17
+
18
+ export type SelectProps<T extends SelectValue = string> = {
17
19
  open?: boolean,
18
20
  name?: string,
19
21
  fullWidth?: boolean,
20
22
  id?: string,
21
23
  onOpenChange?: (open: boolean) => void,
22
- value?: string,
24
+ value?: T,
23
25
  className?: string,
24
26
  inputClassName?: string,
25
27
  onChange?: React.EventHandler<ChangeEvent<HTMLSelectElement>>,
26
- onValueChange?: (updatedValue: string) => void,
28
+ onValueChange?: (updatedValue: T) => void,
27
29
  placeholder?: React.ReactNode,
28
- renderValue?: (value: string) => React.ReactNode,
29
- size?: "small" | "medium" | "large",
30
+ renderValue?: (value: T) => React.ReactNode,
31
+ size?: "smallest" | "small" | "medium" | "large",
30
32
  label?: React.ReactNode | string,
31
33
  disabled?: boolean,
32
34
  error?: boolean,
@@ -39,30 +41,30 @@ export type SelectProps = {
39
41
  };
40
42
 
41
43
  export const Select = forwardRef<HTMLDivElement, SelectProps>(({
42
- inputRef,
43
- open,
44
- name,
45
- fullWidth = false,
46
- id,
47
- onOpenChange,
48
- value,
49
- onChange,
50
- onValueChange,
51
- className,
52
- inputClassName,
53
- placeholder,
54
- renderValue,
55
- label,
56
- size = "large",
57
- error,
58
- disabled,
59
- padding = true,
60
- position = "item-aligned",
61
- endAdornment,
62
- invisible,
63
- children,
64
- ...props
65
- }, ref) => {
44
+ inputRef,
45
+ open,
46
+ name,
47
+ fullWidth = false,
48
+ id,
49
+ onOpenChange,
50
+ value,
51
+ onChange,
52
+ onValueChange,
53
+ className,
54
+ inputClassName,
55
+ placeholder,
56
+ renderValue,
57
+ label,
58
+ size = "large",
59
+ error,
60
+ disabled,
61
+ padding = true,
62
+ position = "item-aligned",
63
+ endAdornment,
64
+ invisible,
65
+ children,
66
+ ...props
67
+ }, ref) => {
66
68
 
67
69
  const [openInternal, setOpenInternal] = useState(open ?? false);
68
70
 
@@ -71,24 +73,32 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
71
73
  }, [open]);
72
74
 
73
75
  const onValueChangeInternal = useCallback((newValue: string) => {
74
- onValueChange?.(newValue);
76
+ // Convert string value to appropriate type
77
+ let typedValue: SelectValue = newValue;
78
+ if (newValue === "true") typedValue = true;
79
+ else if (newValue === "false") typedValue = false;
80
+ else if (!isNaN(Number(newValue)) && newValue.trim() !== '') typedValue = Number(newValue);
81
+
82
+ onValueChange?.(typedValue as any);
75
83
  if (onChange) {
76
84
  const event = {
77
85
  target: {
78
86
  name,
79
- value: newValue
87
+ value: typedValue
80
88
  }
81
- } as ChangeEvent<HTMLSelectElement>;
89
+ } as unknown as ChangeEvent<HTMLSelectElement>;
82
90
  onChange(event);
83
91
  }
84
- }, [onChange, value, onValueChange]);
92
+ }, [onChange, onValueChange, name]);
85
93
 
86
94
  const hasValue = Array.isArray(value) ? value.length > 0 : (value != null && value !== "" && value !== undefined);
95
+ // Convert non-string values to strings for Radix UI
96
+ const stringValue = value !== undefined ? String(value) : undefined;
87
97
 
88
98
  return (
89
99
  <SelectPrimitive.Root
90
100
  name={name}
91
- value={value}
101
+ value={stringValue}
92
102
  open={openInternal}
93
103
  disabled={disabled}
94
104
  onValueChange={onValueChangeInternal}
@@ -105,7 +115,8 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
105
115
  "relative flex items-center",
106
116
  className,
107
117
  {
108
- "min-h-[28px]": size === "small",
118
+ "min-h-[28px]": size === "smallest",
119
+ "min-h-[32px]": size === "small",
109
120
  "min-h-[42px]": size === "medium",
110
121
  "min-h-[64px]": size === "large",
111
122
  "w-fit": !fullWidth,
@@ -122,7 +133,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
122
133
  padding ? {
123
134
  "px-4": size === "large",
124
135
  "px-3": size === "medium",
125
- "px-2": size === "small"
136
+ "px-2": size === "small" || size === "smallest",
126
137
  } : "",
127
138
  "outline-none focus:outline-none",
128
139
  "select-none rounded-md text-sm",
@@ -131,7 +142,8 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
131
142
  disabled ? "text-surface-accent-600 dark:text-surface-accent-400" : "text-surface-accent-800 dark:text-white",
132
143
  "relative flex flex-row items-center",
133
144
  {
134
- "min-h-[28px]": size === "small",
145
+ "min-h-[28px]": size === "smallest",
146
+ "min-h-[32px]": size === "small",
135
147
  "min-h-[42px]": size === "medium",
136
148
  "min-h-[64px]": size === "large",
137
149
  "w-full": fullWidth,
@@ -145,7 +157,8 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
145
157
  "flex-grow max-w-full flex flex-row gap-2 items-center",
146
158
  "overflow-visible",
147
159
  {
148
- "min-h-[28px]": size === "small",
160
+ "min-h-[28px]": size === "smallest",
161
+ "min-h-[32px]": size === "small",
149
162
  "min-h-[42px]": size === "medium",
150
163
  "min-h-[64px]": size === "large"
151
164
  }
@@ -157,10 +170,9 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
157
170
  }}
158
171
  placeholder={placeholder}
159
172
  className={"w-full"}>
160
- {hasValue && value && renderValue ? renderValue(value) : placeholder}
173
+ {hasValue && value !== undefined && renderValue ? renderValue(value) : placeholder}
161
174
  {/*{hasValue && !renderValue && value}*/}
162
175
  {hasValue && !renderValue && (() => {
163
-
164
176
  // @ts-ignore
165
177
  const childrenProps: SelectItemProps[] = Children.map(children, (child) => {
166
178
  if (React.isValidElement(child)) {
@@ -168,7 +180,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
168
180
  }
169
181
  }).filter(Boolean);
170
182
 
171
- const option = childrenProps.find((o) => o.value === value);
183
+ const option = childrenProps.find((o) => String(o.value) === String(value));
172
184
  return option?.children;
173
185
  })()}
174
186
 
@@ -187,10 +199,10 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
187
199
  )}
188
200
  <SelectPrimitive.Icon asChild>
189
201
  <KeyboardArrowDownIcon size={"medium"}
190
- className={cls("transition", open ? "rotate-180" : "", {
191
- "px-2": size === "large",
192
- "px-1": size === "medium" || size === "small",
193
- })}/>
202
+ className={cls("transition", open ? "rotate-180" : "", {
203
+ "px-2": size === "large",
204
+ "px-1": size === "medium" || size === "small",
205
+ })}/>
194
206
  </SelectPrimitive.Icon>
195
207
  </div>
196
208
  </SelectPrimitive.Trigger>
@@ -211,22 +223,25 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
211
223
 
212
224
  Select.displayName = "Select";
213
225
 
214
- export type SelectItemProps = {
215
- value: string,
226
+ export type SelectItemProps<T extends SelectValue = string> = {
227
+ value: T,
216
228
  children?: React.ReactNode,
217
229
  disabled?: boolean,
218
230
  className?: string,
219
231
  };
220
232
 
221
- export function SelectItem({
222
- value,
223
- children,
224
- disabled,
225
- className
226
- }: SelectItemProps) {
233
+ export function SelectItem<T extends SelectValue = string>({
234
+ value,
235
+ children,
236
+ disabled,
237
+ className
238
+ }: SelectItemProps<T>) {
239
+ // Convert value to string for Radix UI
240
+ const stringValue = String(value);
241
+
227
242
  return <SelectPrimitive.Item
228
- key={value}
229
- value={value}
243
+ key={stringValue}
244
+ value={stringValue}
230
245
  disabled={disabled}
231
246
  className={cls(
232
247
  "w-full",
@@ -15,7 +15,9 @@ interface SheetProps {
15
15
  transparent?: boolean;
16
16
  onOpenChange?: (open: boolean) => void;
17
17
  className?: string;
18
+ style?: React.CSSProperties;
18
19
  overlayClassName?: string;
20
+ overlayStyle?: React.CSSProperties;
19
21
  }
20
22
 
21
23
  export const Sheet: React.FC<SheetProps> = ({
@@ -28,7 +30,9 @@ export const Sheet: React.FC<SheetProps> = ({
28
30
  onOpenChange,
29
31
  transparent,
30
32
  className,
33
+ style,
31
34
  overlayClassName,
35
+ overlayStyle,
32
36
  ...props
33
37
  }) => {
34
38
  const [displayed, setDisplayed] = useState(false);
@@ -64,6 +68,7 @@ export const Sheet: React.FC<SheetProps> = ({
64
68
  </DialogPrimitive.Title>
65
69
  {includeBackgroundOverlay && <DialogPrimitive.Overlay
66
70
  className={cls(
71
+ "outline-none",
67
72
  "fixed inset-0 transition-opacity z-20 ease-in-out duration-100 backdrop-blur-sm",
68
73
  "bg-black bg-opacity-50",
69
74
  "dark:bg-surface-900 dark:bg-opacity-60",
@@ -71,13 +76,15 @@ export const Sheet: React.FC<SheetProps> = ({
71
76
  overlayClassName
72
77
  )}
73
78
  style={{
74
- pointerEvents: displayed ? "auto" : "none"
79
+ pointerEvents: displayed ? "auto" : "none",
80
+ ...overlayStyle
75
81
  }}
76
82
  />}
77
83
  <DialogPrimitive.Content
78
84
  {...props}
79
85
  onFocusCapture={(event) => event.preventDefault()}
80
86
  className={cls(
87
+ "outline-none",
81
88
  borderClass[side],
82
89
  defaultBorderMixin,
83
90
  "transform-gpu",
@@ -93,6 +100,7 @@ export const Sheet: React.FC<SheetProps> = ({
93
100
  !displayed || !open ? transformValue[side] : "",
94
101
  className
95
102
  )}
103
+ style={style}
96
104
  >
97
105
  {children}
98
106
  </DialogPrimitive.Content>
@@ -20,6 +20,7 @@ export function Tabs({
20
20
 
21
21
  return <TabsPrimitive.Root value={value} onValueChange={onValueChange} className={className}>
22
22
  <TabsPrimitive.List className={cls(
23
+ "w-max",
23
24
  "flex text-sm font-medium text-center text-surface-accent-800 dark:text-white max-w-full overflow-auto no-scrollbar items-end",
24
25
  innerClassName)
25
26
  }>
@@ -54,7 +55,8 @@ export function Tab({
54
55
  "data-[state=active]:text-surface-accent-900 data-[state=active]:dark:text-white",
55
56
  "hover:text-surface-accent-800 dark:hover:text-surface-accent-200"),
56
57
  className)}>
57
- <div className={cls("uppercase inline-block p-2 px-4 m-2 rounded",
58
+ <div className={cls("line-clamp-1",
59
+ "uppercase inline-block p-2 px-4 rounded",
58
60
  "hover:bg-surface-accent-200 hover:bg-opacity-75 dark:hover:bg-surface-accent-800",
59
61
  innerClassName)}>
60
62
  {children}