@campxdev/react-blueprint 3.0.0-alpha.1 → 3.0.0-alpha.3

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 (52) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/types/src/components/DataDisplay/DataTable/DataTable.d.ts +3 -0
  3. package/dist/cjs/types/src/components/DataDisplay/DataTable/components/TableView.d.ts +3 -0
  4. package/dist/cjs/types/src/components/Input/DatePicker/DatePicker.d.ts +2 -2
  5. package/dist/cjs/types/src/components/Input/DateTimePicker/DateTimePicker.d.ts +2 -2
  6. package/dist/cjs/types/src/components/Input/PasswordField/PasswordField.d.ts +2 -1
  7. package/dist/cjs/types/src/components/Input/TextField/TextField.d.ts +2 -1
  8. package/dist/cjs/types/src/components/Input/Textarea/Textarea.d.ts +12 -0
  9. package/dist/cjs/types/src/components/Input/export.d.ts +1 -0
  10. package/dist/cjs/types/src/components/Layout/AppLayout/index.d.ts +1 -0
  11. package/dist/cjs/types/src/components/Layout/PageHeader/PageHeader.d.ts +3 -2
  12. package/dist/cjs/types/src/components/Navigation/Breadcrumbs/Breadcrumbs.d.ts +3 -1
  13. package/dist/cjs/types/src/shadcn-components/Input/Textarea/Textarea.d.ts +3 -0
  14. package/dist/esm/index.js +2 -2
  15. package/dist/esm/types/src/components/DataDisplay/DataTable/DataTable.d.ts +3 -0
  16. package/dist/esm/types/src/components/DataDisplay/DataTable/components/TableView.d.ts +3 -0
  17. package/dist/esm/types/src/components/Input/DatePicker/DatePicker.d.ts +2 -2
  18. package/dist/esm/types/src/components/Input/DateTimePicker/DateTimePicker.d.ts +2 -2
  19. package/dist/esm/types/src/components/Input/PasswordField/PasswordField.d.ts +2 -1
  20. package/dist/esm/types/src/components/Input/TextField/TextField.d.ts +2 -1
  21. package/dist/esm/types/src/components/Input/Textarea/Textarea.d.ts +12 -0
  22. package/dist/esm/types/src/components/Input/export.d.ts +1 -0
  23. package/dist/esm/types/src/components/Layout/AppLayout/index.d.ts +1 -0
  24. package/dist/esm/types/src/components/Layout/PageHeader/PageHeader.d.ts +3 -2
  25. package/dist/esm/types/src/components/Navigation/Breadcrumbs/Breadcrumbs.d.ts +3 -1
  26. package/dist/esm/types/src/shadcn-components/Input/Textarea/Textarea.d.ts +3 -0
  27. package/dist/index.d.ts +88 -21
  28. package/dist/styles.css +11 -14
  29. package/package.json +1 -1
  30. package/src/components/DataDisplay/DataTable/DataTable.tsx +5 -0
  31. package/src/components/DataDisplay/DataTable/components/TableHeaders/TableActionHeader.tsx +1 -1
  32. package/src/components/DataDisplay/DataTable/components/TableView.tsx +13 -8
  33. package/src/components/DataDisplay/DataTable/components/ViewList/ViewButton.tsx +1 -1
  34. package/src/components/Feedback/Snackbar/Snackbar.tsx +5 -8
  35. package/src/components/Input/DatePicker/DatePicker.tsx +38 -21
  36. package/src/components/Input/DateTimePicker/DateTimePicker.tsx +44 -27
  37. package/src/components/Input/MultiSelect/components/MultiSelectInput.tsx +1 -1
  38. package/src/components/Input/PasswordField/PasswordField.tsx +5 -2
  39. package/src/components/Input/SingleSelect/components/SingleInput.tsx +1 -1
  40. package/src/components/Input/TextField/TextField.tsx +7 -0
  41. package/src/components/Input/Textarea/Textarea.tsx +67 -0
  42. package/src/components/Input/export.ts +1 -0
  43. package/src/components/Layout/AppLayout/components/Sidebar/MenuBar.tsx +1 -0
  44. package/src/components/Layout/AppLayout/components/Sidebar/MenuItem.tsx +2 -2
  45. package/src/components/Layout/AppLayout/components/Sidebar/StyledComponents.tsx +1 -1
  46. package/src/components/Layout/AppLayout/index.ts +3 -0
  47. package/src/components/Layout/PageHeader/PageHeader.tsx +8 -6
  48. package/src/components/Navigation/Breadcrumbs/Breadcrumbs.tsx +17 -6
  49. package/src/components/Navigation/TabsContainer/TabsContainer.tsx +1 -1
  50. package/src/hooks/usePageHeader.ts +1 -1
  51. package/src/shadcn-components/DataDisplay/Typography/Typography.tsx +1 -1
  52. package/src/shadcn-components/Input/Textarea/Textarea.tsx +18 -0
@@ -7,7 +7,7 @@ import {
7
7
  } from '@/shadcn-components/Input/Popover/Popover';
8
8
  import { format as DateFnsFormat } from 'date-fns';
9
9
  import { CalendarDays } from 'lucide-react';
10
- import * as React from 'react';
10
+ import { cloneElement, useEffect, useRef, useState } from 'react';
11
11
  import { Typography } from '../../DataDisplay/Typography/Typography';
12
12
  import { Button } from '../Button/Button';
13
13
  import { LabelWrapper } from '../LabelWrapper/LabelWrapper';
@@ -39,6 +39,7 @@ export type DatePickerProps = {
39
39
  onOpen?: () => void;
40
40
  onClose?: () => void;
41
41
  onBlur?: React.FocusEventHandler;
42
+ fullWidth?: boolean;
42
43
  [key: string]: any;
43
44
  };
44
45
 
@@ -66,10 +67,12 @@ export const DatePicker = ({
66
67
  className,
67
68
  onOpen,
68
69
  onClose,
70
+ fullWidth,
69
71
  ...rest
70
72
  }: DatePickerProps) => {
71
- const [open, setOpen] = React.useState(false);
72
- const [date, setDate] = React.useState<Date | undefined>(value);
73
+ const [open, setOpen] = useState(false);
74
+ const [date, setDate] = useState<Date | undefined>(value);
75
+ const wrapperRef = useRef<HTMLSpanElement>(null);
73
76
 
74
77
  const formatDateString = (date: Date | undefined) => {
75
78
  if (!date) return '';
@@ -90,32 +93,46 @@ export const DatePicker = ({
90
93
  }
91
94
  };
92
95
 
96
+ const [, forceUpdate] = useState({});
97
+ useEffect(() => {
98
+ forceUpdate({});
99
+ }, []);
100
+
93
101
  return (
94
102
  <LabelWrapper
95
103
  label={label}
96
104
  required={required}
97
105
  name={name}
98
- containerProps={containerProps}
106
+ containerProps={{
107
+ ...(fullWidth && { style: { width: '100%' } }),
108
+ ...containerProps,
109
+ }}
99
110
  >
100
111
  <Popover open={open} onOpenChange={handleOpenChange}>
101
112
  <PopoverTrigger asChild>
102
- <Button
103
- variant="input"
104
- className={cn(
105
- 'w-full justify-between text-left font-normal',
106
- // !date && 'text-muted-foreground',
107
- error && 'border-destructive',
108
- className,
109
- )}
110
- disabled={disabled}
111
- {...rest}
113
+ <span
114
+ ref={wrapperRef}
115
+ style={{ display: fullWidth ? 'block' : 'inline-block' }}
112
116
  >
113
- <span>{date ? formatDateString(date) : placeholder}</span>
114
- {Icon &&
115
- React.cloneElement(Icon as React.ReactElement, {
116
- className: 'ml-2 h-4 w-4',
117
- })}
118
- </Button>
117
+ <Button
118
+ variant="input"
119
+ className={cn(
120
+ 'justify-between text-left font-normal',
121
+ !date && 'text-muted-foreground',
122
+ error && 'border-destructive',
123
+ fullWidth ? 'w-full' : 'w-auto',
124
+ className,
125
+ )}
126
+ disabled={disabled}
127
+ {...rest}
128
+ >
129
+ <span>{date ? formatDateString(date) : placeholder}</span>
130
+ {Icon &&
131
+ cloneElement(Icon as React.ReactElement, {
132
+ className: 'ml-2 h-4 w-4',
133
+ })}
134
+ </Button>
135
+ </span>
119
136
  </PopoverTrigger>
120
137
  <PopoverContent className="w-auto p-0" align="start">
121
138
  <div className="flex flex-col">
@@ -199,7 +216,7 @@ export const DatePicker = ({
199
216
  variant="small"
200
217
  className={cn('ml-1 mt-1', error && 'text-destructive')}
201
218
  >
202
- {error || helperText}
219
+ {typeof error === 'string' ? error : error?.message || helperText}
203
220
  </Typography>
204
221
  )}
205
222
  </LabelWrapper>
@@ -8,7 +8,7 @@ import {
8
8
  } from '@/shadcn-components/Input/Popover/Popover';
9
9
  import { format as DateFnsFormat } from 'date-fns';
10
10
  import { CalendarDays } from 'lucide-react';
11
- import * as React from 'react';
11
+ import { cloneElement, useEffect, useMemo, useRef, useState } from 'react';
12
12
  import { Typography } from '../../DataDisplay/Typography/Typography';
13
13
  import { Button } from '../Button/Button';
14
14
  import { LabelWrapper } from '../LabelWrapper/LabelWrapper';
@@ -68,6 +68,7 @@ export type DateTimePickerProps = {
68
68
  onOpen?: () => void;
69
69
  onClose?: () => void;
70
70
  onBlur?: React.FocusEventHandler;
71
+ fullWidth?: boolean;
71
72
  [key: string]: any;
72
73
  };
73
74
 
@@ -96,14 +97,16 @@ export const DateTimePicker = ({
96
97
  className,
97
98
  onOpen,
98
99
  onClose,
100
+ fullWidth,
99
101
  ...rest
100
102
  }: DateTimePickerProps) => {
101
- const [open, setOpen] = React.useState(false);
102
- const [dateTime, setDateTime] = React.useState<Date | undefined>(value);
103
- const [timeValue, setTimeValue] = React.useState<string>('');
103
+ const [open, setOpen] = useState(false);
104
+ const [dateTime, setDateTime] = useState<Date | undefined>(value);
105
+ const [timeValue, setTimeValue] = useState<string>('');
106
+ const wrapperRef = useRef<HTMLSpanElement>(null);
104
107
 
105
108
  // Determine view configurations based on views prop
106
- const viewConfig = React.useMemo(() => {
109
+ const viewConfig = useMemo(() => {
107
110
  const hasTime =
108
111
  views.includes('hours') ||
109
112
  views.includes('minutes') ||
@@ -120,7 +123,7 @@ export const DateTimePicker = ({
120
123
  }, [views]);
121
124
 
122
125
  // Update time value when dateTime changes
123
- React.useEffect(() => {
126
+ useEffect(() => {
124
127
  if (dateTime && viewConfig.showTime) {
125
128
  const hours = dateTime.getHours(),
126
129
  minutes = dateTime.getMinutes(),
@@ -184,6 +187,11 @@ export const DateTimePicker = ({
184
187
  }
185
188
  };
186
189
 
190
+ const [, forceUpdate] = useState({});
191
+ useEffect(() => {
192
+ forceUpdate({});
193
+ }, []);
194
+
187
195
  // If only time selection (no date), render native time input directly
188
196
  if (viewConfig.showTime && !viewConfig.showDate) {
189
197
  return (
@@ -214,7 +222,7 @@ export const DateTimePicker = ({
214
222
  variant="small"
215
223
  className={cn('ml-1 mt-1', error && 'text-destructive')}
216
224
  >
217
- {error || helperText}
225
+ {typeof error === 'string' ? error : error?.message || helperText}
218
226
  </Typography>
219
227
  )}
220
228
  </LabelWrapper>
@@ -226,29 +234,38 @@ export const DateTimePicker = ({
226
234
  label={label}
227
235
  required={required}
228
236
  name={name}
229
- containerProps={containerProps}
237
+ containerProps={{
238
+ ...(fullWidth && { style: { width: '100%' } }),
239
+ ...containerProps,
240
+ }}
230
241
  >
231
242
  <Popover open={open} onOpenChange={handleOpenChange}>
232
243
  <PopoverTrigger asChild>
233
- <Button
234
- variant="input"
235
- className={cn(
236
- 'w-full justify-between text-left font-normal',
237
- !dateTime && 'text-muted-foreground',
238
- error && 'border-destructive',
239
- className,
240
- )}
241
- disabled={disabled}
242
- {...rest}
244
+ <span
245
+ ref={wrapperRef}
246
+ style={{ display: fullWidth ? 'block' : 'inline-block' }}
243
247
  >
244
- <span>
245
- {dateTime ? formatDateTimeString(dateTime) : placeholder}
246
- </span>
247
- {Icon &&
248
- React.cloneElement(Icon as React.ReactElement, {
249
- className: 'ml-2 h-4 w-4 ',
250
- })}
251
- </Button>
248
+ <Button
249
+ variant="input"
250
+ className={cn(
251
+ 'w-full justify-between text-left font-normal',
252
+ !dateTime && 'text-muted-foreground',
253
+ error && 'border-destructive',
254
+ fullWidth ? 'w-full' : 'w-auto',
255
+ className,
256
+ )}
257
+ disabled={disabled}
258
+ {...rest}
259
+ >
260
+ <span>
261
+ {dateTime ? formatDateTimeString(dateTime) : placeholder}
262
+ </span>
263
+ {Icon &&
264
+ cloneElement(Icon as React.ReactElement, {
265
+ className: 'ml-2 h-4 w-4 ',
266
+ })}
267
+ </Button>
268
+ </span>
252
269
  </PopoverTrigger>
253
270
  <PopoverContent className="w-auto p-0" align="start">
254
271
  <div className="flex flex-col">
@@ -334,7 +351,7 @@ export const DateTimePicker = ({
334
351
  variant="small"
335
352
  className={cn('ml-1 mt-1', error && 'text-destructive')}
336
353
  >
337
- {error || helperText}
354
+ {typeof error === 'string' ? error : error?.message || helperText}
338
355
  </Typography>
339
356
  )}
340
357
  </LabelWrapper>
@@ -232,7 +232,7 @@ export const MultiSelectInput = ({
232
232
  variant="muted"
233
233
  className={cn('text-xs', error && 'text-destructive')}
234
234
  >
235
- {error || helperText}
235
+ {typeof error === 'string' ? error : error?.message || helperText}
236
236
  </Typography>
237
237
  )}
238
238
  </LabelWrapper>
@@ -18,6 +18,7 @@ export type PasswordFieldProps = {
18
18
  error?: boolean;
19
19
  helperText?: string;
20
20
  className?: string;
21
+ fullWidth?: boolean;
21
22
  } & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'>;
22
23
 
23
24
  export const PasswordField = ({
@@ -33,6 +34,7 @@ export const PasswordField = ({
33
34
  error = false,
34
35
  helperText,
35
36
  className,
37
+ fullWidth,
36
38
  ...rest
37
39
  }: PasswordFieldProps) => {
38
40
  const [showPassword, setShowPassword] = useState(false);
@@ -42,8 +44,8 @@ export const PasswordField = ({
42
44
  };
43
45
 
44
46
  const content = (
45
- <div className="flex flex-col gap-2">
46
- <div className="relative">
47
+ <div className={cn('flex flex-col gap-2', fullWidth && 'w-full')}>
48
+ <div className={cn('relative', fullWidth && 'w-full')}>
47
49
  <Input
48
50
  id={name}
49
51
  name={name}
@@ -53,6 +55,7 @@ export const PasswordField = ({
53
55
  placeholder={placeholder}
54
56
  disabled={disabled}
55
57
  className={cn(
58
+ fullWidth && 'w-full',
56
59
  'pr-10 bg-input-background border-none ',
57
60
  error && 'border-destructive focus-visible:ring-destructive',
58
61
  className,
@@ -198,7 +198,7 @@ export const SingleInput = ({
198
198
  variant="muted"
199
199
  className={cn('text-xs', error && 'text-destructive')}
200
200
  >
201
- {error || helperText}
201
+ {typeof error === 'string' ? error : error?.message || helperText}
202
202
  </Typography>
203
203
  )}
204
204
  </LabelWrapper>
@@ -11,6 +11,7 @@ export type TextFieldProps = {
11
11
  required?: boolean;
12
12
  fullWidth?: boolean;
13
13
  error?: boolean;
14
+ helperText?: React.ReactNode;
14
15
  } & React.ComponentProps<typeof Input>;
15
16
 
16
17
  export const TextField = ({
@@ -24,6 +25,7 @@ export const TextField = ({
24
25
  fullWidth,
25
26
  className,
26
27
  error = false,
28
+ helperText,
27
29
  ...rest
28
30
  }: TextFieldProps) => {
29
31
  return (
@@ -50,6 +52,11 @@ export const TextField = ({
50
52
  aria-invalid={error}
51
53
  {...rest}
52
54
  />
55
+ {helperText && (
56
+ <Typography variant="muted" className={cn(error && 'text-destructive')}>
57
+ {helperText}
58
+ </Typography>
59
+ )}
53
60
  {description && (
54
61
  <Typography variant="muted" className={cn(error && 'text-destructive')}>
55
62
  {description}
@@ -0,0 +1,67 @@
1
+ import { cn } from '@/lib/utils';
2
+ import { Typography } from '@/shadcn-components/DataDisplay/Typography/Typography';
3
+ import { Textarea as ShadcnTextarea } from '@/shadcn-components/Input/Textarea/Textarea';
4
+ import * as React from 'react';
5
+ import { LabelWrapper } from '../LabelWrapper/LabelWrapper';
6
+
7
+ export type TextareaProps = {
8
+ containerProps?: React.HTMLAttributes<HTMLDivElement>;
9
+ description?: string;
10
+ label?: React.ReactNode | string;
11
+ required?: boolean;
12
+ fullWidth?: boolean;
13
+ error?: boolean;
14
+ helperText?: React.ReactNode;
15
+ } & React.ComponentProps<typeof ShadcnTextarea>;
16
+
17
+ export const Textarea = ({
18
+ name,
19
+ label,
20
+ value,
21
+ onChange,
22
+ required = false,
23
+ containerProps,
24
+ description,
25
+ fullWidth,
26
+ className,
27
+ error = false,
28
+ helperText,
29
+ ...rest
30
+ }: TextareaProps) => {
31
+ return (
32
+ <LabelWrapper
33
+ label={label}
34
+ required={required}
35
+ name={name}
36
+ containerProps={{
37
+ ...(fullWidth && { style: { width: '100%' } }),
38
+ ...containerProps,
39
+ }}
40
+ >
41
+ <ShadcnTextarea
42
+ id={name}
43
+ value={value}
44
+ name={name}
45
+ onChange={onChange}
46
+ className={cn(
47
+ fullWidth && 'w-full',
48
+ 'bg-input-background border-none placeholder:text-muted-foreground',
49
+ className,
50
+ )}
51
+ required={required}
52
+ aria-invalid={error}
53
+ {...rest}
54
+ />
55
+ {helperText && (
56
+ <Typography variant="muted" className={cn(error && 'text-destructive')}>
57
+ {helperText}
58
+ </Typography>
59
+ )}
60
+ {description && (
61
+ <Typography variant="muted" className={cn(error && 'text-destructive')}>
62
+ {description}
63
+ </Typography>
64
+ )}
65
+ </LabelWrapper>
66
+ );
67
+ };
@@ -17,4 +17,5 @@ export * from './Select/Select';
17
17
  export * from './SingleCheckBox/SingleCheckBox';
18
18
  export * from './SingleSelect/SingleSelect';
19
19
  export * from './Switch/Switch';
20
+ export * from './Textarea/Textarea';
20
21
  export * from './TextField/TextField';
@@ -54,6 +54,7 @@ export const MenuBar: React.FC<MenuBarProps> = ({
54
54
  variants={containerVariants}
55
55
  initial="hidden"
56
56
  animate="visible"
57
+ className="flex flex-col gap-1"
57
58
  >
58
59
  {currentMenuState.menu.map((item, index) => (
59
60
  <MenuItem
@@ -3,7 +3,7 @@ import { useState } from 'react';
3
3
  import { useMatch, useResolvedPath } from 'react-router-dom';
4
4
 
5
5
  import { cn } from '@/lib/utils';
6
- import { Minus, Plus, Undo2 } from 'lucide-react';
6
+ import { ChevronDown, ChevronUp, Undo2 } from 'lucide-react';
7
7
  import { Typography } from '../../../../DataDisplay/Typography/Typography';
8
8
  import { Tooltip } from '../../../../Feedback/Tooltip/Tooltip';
9
9
  import { MenuItemProps } from './interfaces';
@@ -135,7 +135,7 @@ export const MenuItem: React.FC<MenuItemProps> = ({
135
135
  <Typography variant={'small'}>{name}</Typography>
136
136
  </div>
137
137
  <div className="flex flex-col">
138
- {expanded ? <Minus /> : <Plus />}
138
+ {expanded ? <ChevronDown /> : <ChevronUp />}
139
139
  </div>
140
140
  </div>
141
141
  )}
@@ -198,7 +198,7 @@ export const SubMenuItemContainer: React.FC<BaseProps> = ({
198
198
  return (
199
199
  <div
200
200
  className={cn(
201
- 'flex flex-col ml-6 border-l-2 border-border/10',
201
+ 'flex flex-col gap-1 ml-6 border-l-2 border-border/10',
202
202
  className,
203
203
  )}
204
204
  {...props}
@@ -10,3 +10,6 @@ export { MenuToggleButton } from './components/MenuToggleButton';
10
10
 
11
11
  // Reusable popup components for AppLayout right section
12
12
  export { UserProfilePopup } from './components/UserProfilePopup';
13
+
14
+ // Sidebar interfaces
15
+ export * from './components/Sidebar/interfaces';
@@ -17,7 +17,8 @@ import { PageHeaderSearchBar } from './components/SearchBar';
17
17
  interface PageHeaderProps {
18
18
  uniqueId?: string;
19
19
  pathTrimCount: number;
20
- searchButtonProps?: SearchBarProps;
20
+ breadcrumbAction?: ReactElement;
21
+ searchBarProps?: SearchBarProps;
21
22
  filterButtonProps?: {
22
23
  label?: string;
23
24
  startIcon?: ReactNode;
@@ -35,7 +36,8 @@ interface PageHeaderProps {
35
36
  const PageHeader = ({
36
37
  uniqueId,
37
38
  pathTrimCount,
38
- searchButtonProps,
39
+ breadcrumbAction,
40
+ searchBarProps,
39
41
  filterButtonProps,
40
42
  addButtonProps,
41
43
  actionProps,
@@ -44,7 +46,7 @@ const PageHeader = ({
44
46
  const dispatch = useDispatch();
45
47
 
46
48
  const showActionBar =
47
- searchButtonProps || filterButtonProps || addButtonProps || actionProps;
49
+ searchBarProps || filterButtonProps || addButtonProps || actionProps;
48
50
 
49
51
  const wrapProps = (element: ReactElement): ReactElement => {
50
52
  const { name } = element.props;
@@ -66,19 +68,19 @@ const PageHeader = ({
66
68
 
67
69
  return (
68
70
  <div>
69
- <Breadcrumbs pathTrimCount={pathTrimCount} />
71
+ <Breadcrumbs pathTrimCount={pathTrimCount} action={breadcrumbAction} />
70
72
  <div
71
73
  className={cn(
72
74
  'flex flex-col md:flex-row gap-1 md:gap-2 items-center w-full px-1 pb-2 md:p-0 border-b',
73
75
  showActionBar ? '' : 'hidden',
74
76
  )}
75
77
  >
76
- {searchButtonProps && (
78
+ {searchBarProps && (
77
79
  <PageHeaderSearchBar
78
80
  className="w-full"
79
81
  containerClassName="w-full md:w-md"
80
82
  uniqueId={uniqueId}
81
- {...searchButtonProps}
83
+ {...searchBarProps}
82
84
  />
83
85
  )}
84
86
  <div className="flex gap-2 items-center w-full px-2 md:p-0">
@@ -18,17 +18,20 @@ import {
18
18
  DropdownMenuItem,
19
19
  DropdownMenuTrigger,
20
20
  } from '@/shadcn-components/Navigation/DropdownMenu/DropdownMenu';
21
+ import { ReactElement } from 'react';
21
22
  import { getBreadcrumbsCharacter } from '../../../utils/export';
22
23
  import { MenuToggleButton } from '../../Layout/AppLayout/components/MenuToggleButton';
23
24
 
24
25
  export type BreadcrumbsProps = {
25
26
  pathTrimCount: number;
26
27
  containerClassName?: string;
28
+ action?: ReactElement;
27
29
  };
28
30
 
29
31
  export const Breadcrumbs = ({
30
32
  pathTrimCount,
31
33
  containerClassName,
34
+ action,
32
35
  }: BreadcrumbsProps) => {
33
36
  const specialCharacter = getBreadcrumbsCharacter();
34
37
  const currentPathArray = window.location.pathname.split('/');
@@ -87,7 +90,7 @@ export const Breadcrumbs = ({
87
90
  <BreadcrumbItem>
88
91
  <DropdownMenu>
89
92
  <DropdownMenuTrigger className="flex items-center gap-1">
90
- <BreadcrumbEllipsis />
93
+ <BreadcrumbEllipsis className="size-5" />
91
94
  </DropdownMenuTrigger>
92
95
  <DropdownMenuContent align="start">
93
96
  {middleItems.map((item, index) => (
@@ -112,14 +115,22 @@ export const Breadcrumbs = ({
112
115
  return (
113
116
  <div
114
117
  className={cn(
115
- 'flex w-full flex-row items-center px-2 pt-2 gap-1 md:px-3',
118
+ 'flex w-full flex-row items-center justify-between px-2 pt-2 gap-1 md:px-3',
116
119
  containerClassName,
117
120
  )}
118
121
  >
119
- <MenuToggleButton />
120
- <Breadcrumb>
121
- <BreadcrumbList>{renderBreadcrumbs()}</BreadcrumbList>
122
- </Breadcrumb>
122
+ <div
123
+ className={cn(
124
+ 'flex w-full flex-row items-center gap-1 md:px-3',
125
+ containerClassName,
126
+ )}
127
+ >
128
+ <MenuToggleButton />
129
+ <Breadcrumb>
130
+ <BreadcrumbList>{renderBreadcrumbs()}</BreadcrumbList>
131
+ </Breadcrumb>
132
+ </div>
133
+ {action}
123
134
  </div>
124
135
  );
125
136
  };
@@ -55,7 +55,7 @@ export const TabsContainer = ({
55
55
  <Tabs
56
56
  value={currentTab}
57
57
  onValueChange={handleTabsChange}
58
- className={cn('mt-0 md:mt-2', className)}
58
+ className={className}
59
59
  >
60
60
  <TabsList className={cn(tabsListClassName)} style={{ margin: '4px 8px' }}>
61
61
  {tabs.map(({ key, label, highlight, disabled, icon }) => (
@@ -6,9 +6,9 @@ import {
6
6
  PageHeaderSingleState,
7
7
  resetStateForUniqueId,
8
8
  setDefaultFiltersForUniqueId,
9
+ setLayoutModeForUniqueId,
9
10
  setLimitForUniqueId,
10
11
  setOffsetForUniqueId,
11
- setLayoutModeForUniqueId,
12
12
  } from '../redux/slices/pageHeaderSlice';
13
13
  import { RootState } from '../redux/store';
14
14
 
@@ -12,7 +12,7 @@ const typographyVariants = cva('', {
12
12
  h4: 'scroll-m-20 text-xl font-semibold tracking-tight',
13
13
 
14
14
  // Paragraphs
15
- p: 'leading-7 [&:not(:first-child)]:mt-6',
15
+ p: 'leading-7',
16
16
 
17
17
  // Quote
18
18
  blockquote: 'mt-6 border-l-2 pl-6 italic',
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '@/lib/utils';
4
+
5
+ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
6
+ return (
7
+ <textarea
8
+ data-slot="textarea"
9
+ className={cn(
10
+ 'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
11
+ className,
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ export { Textarea };