@firecms/ui 3.0.0-canary.13 → 3.0.0-canary.130

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 (103) hide show
  1. package/README.md +2 -2
  2. package/dist/components/Avatar.d.ts +1 -0
  3. package/dist/components/BooleanSwitch.d.ts +1 -1
  4. package/dist/components/CenteredView.d.ts +4 -2
  5. package/dist/components/Checkbox.d.ts +3 -2
  6. package/dist/components/Chip.d.ts +3 -2
  7. package/dist/components/DateTimeField.d.ts +5 -7
  8. package/dist/components/Dialog.d.ts +4 -1
  9. package/dist/components/InputLabel.d.ts +2 -2
  10. package/dist/components/Label.d.ts +4 -1
  11. package/dist/components/Markdown.d.ts +1 -0
  12. package/dist/components/Menu.d.ts +6 -2
  13. package/dist/components/Menubar.d.ts +79 -0
  14. package/dist/components/MultiSelect.d.ts +31 -16
  15. package/dist/components/Popover.d.ts +2 -1
  16. package/dist/components/RadioGroup.d.ts +26 -3
  17. package/dist/components/Select.d.ts +6 -10
  18. package/dist/components/Separator.d.ts +2 -1
  19. package/dist/components/Sheet.d.ts +4 -0
  20. package/dist/components/Table.d.ts +10 -10
  21. package/dist/components/TextField.d.ts +1 -1
  22. package/dist/components/TextareaAutosize.d.ts +3 -34
  23. package/dist/components/Tooltip.d.ts +6 -2
  24. package/dist/components/_MultiSelect.d.ts +0 -0
  25. package/dist/components/index.d.ts +1 -1
  26. package/dist/hooks/index.d.ts +4 -0
  27. package/dist/hooks/useLocaleConfig.d.ts +1 -0
  28. package/dist/icons/Icon.d.ts +3 -3
  29. package/dist/index.css +77 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.es.js +13178 -13542
  32. package/dist/index.es.js.map +1 -1
  33. package/dist/index.umd.js +19685 -49
  34. package/dist/index.umd.js.map +1 -1
  35. package/dist/styles.d.ts +7 -7
  36. package/dist/util/{cn.d.ts → cls.d.ts} +4 -0
  37. package/dist/util/index.d.ts +1 -3
  38. package/package.json +109 -118
  39. package/src/components/Alert.tsx +2 -2
  40. package/src/components/Autocomplete.tsx +4 -3
  41. package/src/components/Avatar.tsx +7 -6
  42. package/src/components/Badge.tsx +1 -1
  43. package/src/components/BooleanSwitch.tsx +15 -15
  44. package/src/components/BooleanSwitchWithLabel.tsx +8 -8
  45. package/src/components/Button.tsx +18 -20
  46. package/src/components/Card.tsx +3 -3
  47. package/src/components/CenteredView.tsx +25 -15
  48. package/src/components/Checkbox.tsx +11 -9
  49. package/src/components/Chip.tsx +8 -5
  50. package/src/components/CircularProgress.tsx +2 -2
  51. package/src/components/Collapse.tsx +3 -2
  52. package/src/components/Container.tsx +2 -2
  53. package/src/components/DateTimeField.tsx +45 -50
  54. package/src/components/Dialog.tsx +15 -6
  55. package/src/components/DialogActions.tsx +2 -2
  56. package/src/components/DialogContent.tsx +2 -2
  57. package/src/components/ExpandablePanel.tsx +10 -8
  58. package/src/components/FileUpload.tsx +6 -9
  59. package/src/components/IconButton.tsx +4 -6
  60. package/src/components/InfoLabel.tsx +2 -2
  61. package/src/components/InputLabel.tsx +12 -9
  62. package/src/components/Label.tsx +17 -4
  63. package/src/components/Markdown.tsx +14 -3
  64. package/src/components/Menu.tsx +49 -31
  65. package/src/components/Menubar.tsx +322 -0
  66. package/src/components/MultiSelect.tsx +335 -165
  67. package/src/components/Paper.tsx +2 -2
  68. package/src/components/Popover.tsx +17 -14
  69. package/src/components/RadioGroup.tsx +41 -9
  70. package/src/components/SearchBar.tsx +8 -9
  71. package/src/components/Select.tsx +105 -125
  72. package/src/components/Separator.tsx +10 -4
  73. package/src/components/Sheet.tsx +45 -28
  74. package/src/components/Skeleton.tsx +9 -6
  75. package/src/components/Table.tsx +50 -33
  76. package/src/components/Tabs.tsx +6 -7
  77. package/src/components/TextField.tsx +10 -13
  78. package/src/components/TextareaAutosize.tsx +3 -3
  79. package/src/components/Tooltip.tsx +30 -14
  80. package/src/components/Typography.tsx +34 -19
  81. package/src/components/_MultiSelect.tsx +222 -0
  82. package/src/components/common/SelectInputLabel.tsx +2 -2
  83. package/src/components/index.tsx +1 -1
  84. package/src/hooks/index.ts +4 -0
  85. package/src/hooks/useLocaleConfig.tsx +18 -0
  86. package/src/icons/Icon.tsx +46 -43
  87. package/src/icons/icon_keys.ts +114 -1301
  88. package/src/index.css +77 -0
  89. package/src/index.ts +1 -0
  90. package/src/scripts/generateIconKeys.ts +20 -11
  91. package/src/styles.ts +7 -7
  92. package/src/util/cls.ts +14 -0
  93. package/src/util/index.ts +1 -3
  94. package/tailwind.config.js +8 -6
  95. package/dist/components/Spinner.d.ts +0 -1
  96. package/src/components/Spinner.tsx +0 -18
  97. package/src/util/cn.ts +0 -6
  98. /package/dist/{util → hooks}/useDebounceValue.d.ts +0 -0
  99. /package/dist/{util → hooks}/useInjectStyles.d.ts +0 -0
  100. /package/dist/{util → hooks}/useOutsideAlerter.d.ts +0 -0
  101. /package/src/{util → hooks}/useDebounceValue.tsx +0 -0
  102. /package/src/{util → hooks}/useInjectStyles.tsx +0 -0
  103. /package/src/{util → hooks}/useOutsideAlerter.tsx +0 -0
@@ -1,15 +1,36 @@
1
1
  import * as React from "react"
2
2
  import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
3
- import { cn } from "../util";
4
- import { CircleIcon } from "../icons";
3
+ import { cls } from "../util";
4
+
5
+ export interface RadioGroupProps {
6
+ id?: string;
7
+ children: React.ReactNode;
8
+ name?: string
9
+ required?: boolean;
10
+ disabled?: boolean;
11
+ /**
12
+ * Whether keyboard navigation should loop around
13
+ * @defaultValue false
14
+ */
15
+ loop?: boolean;
16
+ defaultValue?: string;
17
+ value?: string;
18
+
19
+ onValueChange?(value: string): void;
20
+
21
+ className?: string;
22
+ }
5
23
 
6
24
  const RadioGroup = React.forwardRef<
7
25
  React.ElementRef<typeof RadioGroupPrimitive.Root>,
8
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
9
- >(({ className, ...props }, ref) => {
26
+ RadioGroupProps
27
+ >(({
28
+ className,
29
+ ...props
30
+ }, ref) => {
10
31
  return (
11
32
  <RadioGroupPrimitive.Root
12
- className={cn("grid gap-2", className)}
33
+ className={cls("grid gap-2", className)}
13
34
  {...props}
14
35
  ref={ref}
15
36
  />
@@ -17,21 +38,32 @@ const RadioGroup = React.forwardRef<
17
38
  })
18
39
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
19
40
 
41
+ export interface RadioGroupItemProps {
42
+ id?: string;
43
+ value: string;
44
+ checked?: boolean;
45
+ required?: boolean;
46
+ className?: string;
47
+ disabled?: boolean;
48
+ }
20
49
  const RadioGroupItem = React.forwardRef<
21
50
  React.ElementRef<typeof RadioGroupPrimitive.Item>,
22
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
23
- >(({ className, ...props }, ref) => {
51
+ RadioGroupItemProps
52
+ >(({
53
+ className,
54
+ ...props
55
+ }, ref) => {
24
56
  return (
25
57
  <RadioGroupPrimitive.Item
26
58
  ref={ref}
27
- className={cn(
59
+ className={cls(
28
60
  "aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
29
61
  className
30
62
  )}
31
63
  {...props}
32
64
  >
33
65
  <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
34
- <div className="h-2.5 w-2.5 fill-current text-current bg-primary rounded-lg" />
66
+ <div className="h-2.5 w-2.5 fill-current text-current bg-primary rounded-lg"/>
35
67
  </RadioGroupPrimitive.Indicator>
36
68
  </RadioGroupPrimitive.Item>
37
69
  )
@@ -1,10 +1,10 @@
1
1
  import React, { useCallback, useState } from "react";
2
2
 
3
- import { defaultBorderMixin, focusedMixin } from "../styles";
3
+ import { defaultBorderMixin } from "../styles";
4
4
  import { CircularProgress, IconButton } from "./index";
5
5
  import { ClearIcon, SearchIcon } from "../icons";
6
- import { cn } from "../util";
7
- import { useDebounceValue } from "../util/useDebounceValue";
6
+ import { cls } from "../util";
7
+ import { useDebounceValue } from "../hooks";
8
8
 
9
9
  interface SearchBarProps {
10
10
  onClick?: () => void;
@@ -60,14 +60,14 @@ export function SearchBar({
60
60
  return (
61
61
  <div
62
62
  onClick={onClick}
63
- className={cn("relative",
63
+ className={cls("relative",
64
64
  large ? "h-14" : "h-[42px]",
65
- "bg-slate-50 dark:bg-gray-800 transition duration-150 ease-in-out border",
65
+ "bg-slate-50 dark:bg-gray-800 border",
66
66
  defaultBorderMixin,
67
- "rounded",
67
+ "rounded-lg",
68
68
  className)}>
69
69
  <div
70
- className="absolute p-0 px-4 h-full absolute pointer-events-none flex items-center justify-center top-0">
70
+ className="absolute p-0 px-4 h-full pointer-events-none flex items-center justify-center top-0">
71
71
  {loading ? <CircularProgress size={"small"}/> : <SearchIcon className={"text-slate-500 dark:text-gray-500"}/>}
72
72
  </div>
73
73
  <input
@@ -84,12 +84,11 @@ export function SearchBar({
84
84
  autoFocus={autoFocus}
85
85
  onFocus={() => setActive(true)}
86
86
  onBlur={() => setActive(false)}
87
- className={cn(
87
+ className={cls(
88
88
  (disabled || loading) && "pointer-events-none",
89
89
  "relative flex items-center rounded transition-all bg-transparent outline-none appearance-none border-none",
90
90
  "pl-12 h-full text-current ",
91
91
  expandable ? (active ? "w-[220px]" : "w-[180px]") : "",
92
- focusedMixin,
93
92
  innerClassName
94
93
  )}
95
94
  />
@@ -1,15 +1,15 @@
1
- import React, { useEffect } from "react";
2
-
1
+ import React, { ChangeEvent, forwardRef, useCallback, useEffect, useState } from "react";
3
2
  import * as SelectPrimitive from "@radix-ui/react-select";
4
3
  import {
4
+ defaultBorderMixin,
5
5
  fieldBackgroundDisabledMixin,
6
6
  fieldBackgroundHoverMixin,
7
7
  fieldBackgroundInvisibleMixin,
8
8
  fieldBackgroundMixin,
9
- focusedMixin
9
+ focusedDisabled
10
10
  } from "../styles";
11
11
  import { CheckIcon, ExpandMoreIcon } from "../icons";
12
- import { cn } from "../util";
12
+ import { cls } from "../util";
13
13
  import { SelectInputLabel } from "./common/SelectInputLabel";
14
14
 
15
15
  export type SelectProps = {
@@ -17,89 +17,75 @@ export type SelectProps = {
17
17
  name?: string,
18
18
  id?: string,
19
19
  onOpenChange?: (open: boolean) => void,
20
- value?: string | string[],
20
+ value?: string,
21
21
  className?: string,
22
22
  inputClassName?: string,
23
- onChange?: React.EventHandler<React.ChangeEvent<HTMLSelectElement>>,
23
+ onChange?: React.EventHandler<ChangeEvent<HTMLSelectElement>>,
24
24
  onValueChange?: (updatedValue: string) => void,
25
- onMultiValueChange?: (updatedValue: string[]) => void,
26
25
  placeholder?: React.ReactNode,
27
- renderValue?: (value: string, index: number) => React.ReactNode,
28
- renderValues?: (values: string[]) => React.ReactNode,
26
+ renderValue?: (value: string) => React.ReactNode,
29
27
  size?: "small" | "medium",
30
- label?: React.ReactNode,
28
+ label?: React.ReactNode | string,
31
29
  disabled?: boolean,
32
30
  error?: boolean,
33
31
  position?: "item-aligned" | "popper",
34
32
  endAdornment?: React.ReactNode,
35
- multiple?: boolean,
36
33
  inputRef?: React.RefObject<HTMLButtonElement>,
37
34
  padding?: boolean,
38
- includeFocusOutline?: boolean,
39
35
  invisible?: boolean,
40
- children?: React.ReactNode
36
+ children?: React.ReactNode;
41
37
  };
42
38
 
43
- export function Select({
44
- inputRef,
45
- open,
46
- name,
47
- id,
48
- onOpenChange,
49
- value,
50
- onChange,
51
- onValueChange,
52
- onMultiValueChange,
53
- className,
54
- inputClassName,
55
- placeholder,
56
- renderValue,
57
- renderValues,
58
- label,
59
- size = "medium",
60
- includeFocusOutline = true,
61
- error,
62
- disabled,
63
- padding = true,
64
- position = "item-aligned",
65
- endAdornment,
66
- multiple,
67
- invisible,
68
- children,
69
- ...props
70
- }: SelectProps) {
39
+ export const Select = forwardRef<HTMLDivElement, SelectProps>(({
40
+ inputRef,
41
+ open,
42
+ name,
43
+ id,
44
+ onOpenChange,
45
+ value,
46
+ onChange,
47
+ onValueChange,
48
+ className,
49
+ inputClassName,
50
+ placeholder,
51
+ renderValue,
52
+ label,
53
+ size = "medium",
54
+ error,
55
+ disabled,
56
+ padding = true,
57
+ position = "item-aligned",
58
+ endAdornment,
59
+ invisible,
60
+ children,
61
+ ...props
62
+ }, ref) => {
63
+
64
+ const [openInternal, setOpenInternal] = useState(open ?? false);
71
65
 
72
- const [openInternal, setOpenInternal] = React.useState(false);
73
66
  useEffect(() => {
74
67
  setOpenInternal(open ?? false);
75
68
  }, [open]);
76
69
 
77
- const onValueChangeInternal = React.useCallback((newValue: string) => {
78
- if (multiple) {
79
- if (Array.isArray(value) && value.includes(newValue)) {
80
- onMultiValueChange?.(value.filter(v => v !== newValue));
81
- } else {
82
- onMultiValueChange?.([...(value as string[] ?? []), newValue]);
83
- }
84
- } else {
85
- onValueChange?.(newValue);
86
- }
87
- if (!multiple && onChange) {
70
+ const onValueChangeInternal = useCallback((newValue: string) => {
71
+ onValueChange?.(newValue);
72
+ if (onChange) {
88
73
  const event = {
89
74
  target: {
90
75
  name,
91
76
  value: newValue
92
77
  }
93
- } as React.ChangeEvent<HTMLSelectElement>;
78
+ } as ChangeEvent<HTMLSelectElement>;
94
79
  onChange(event);
95
80
  }
96
- }, [multiple, onChange, value, onMultiValueChange, onValueChange]);
81
+ }, [onChange, value, onValueChange]);
82
+
83
+ const hasValue = Array.isArray(value) ? value.length > 0 : value != null;
97
84
 
98
85
  return (
99
86
  <SelectPrimitive.Root
100
87
  name={name}
101
- value={Array.isArray(value) ? undefined : value}
102
- defaultOpen={open}
88
+ value={value}
103
89
  open={openInternal}
104
90
  disabled={disabled}
105
91
  onValueChange={onValueChangeInternal}
@@ -107,23 +93,22 @@ export function Select({
107
93
  onOpenChange?.(open);
108
94
  setOpenInternal(open);
109
95
  }}
110
- {...props}>
111
-
96
+ {...props}
97
+ >
112
98
  {typeof label === "string" ? <SelectInputLabel error={error}>{label}</SelectInputLabel> : label}
113
-
114
- <div
115
- className={cn(
116
- size === "small" ? "min-h-[42px]" : "min-h-[64px]",
117
- "select-none rounded-md text-sm",
118
- invisible ? fieldBackgroundInvisibleMixin : fieldBackgroundMixin,
119
- disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
120
- "relative flex items-center",
121
- className)}>
122
-
99
+ <div className={cls(
100
+ size === "small" ? "min-h-[42px]" : "min-h-[64px]",
101
+ "select-none rounded-md text-sm",
102
+ invisible ? fieldBackgroundInvisibleMixin : fieldBackgroundMixin,
103
+ disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
104
+ "relative flex items-center",
105
+ className
106
+ )}
107
+ >
123
108
  <SelectPrimitive.Trigger
124
109
  ref={inputRef}
125
110
  id={id}
126
- className={cn(
111
+ className={cls(
127
112
  "w-full h-full",
128
113
  size === "small" ? "h-[42px]" : "h-[64px]",
129
114
  padding ? "px-4 " : "",
@@ -133,65 +118,62 @@ export function Select({
133
118
  error ? "border border-red-500 dark:border-red-600" : "",
134
119
  disabled ? "text-slate-600 dark:text-slate-400" : "text-slate-800 dark:text-white",
135
120
  "relative flex items-center",
136
- includeFocusOutline ? focusedMixin : "",
137
121
  inputClassName
138
- )}>
139
-
140
- <div className={cn(
141
- "flex-grow w-full max-w-full flex flex-row gap-2 items-center",
142
- "overflow-visible",
143
- size === "small" ? "h-[42px]" : "h-[64px]"
144
- )}>
145
- <SelectPrimitive.Value >
146
- {renderValue &&
147
- (value && Array.isArray(value)
148
- ? value.map((v, i) => (
149
- <div key={v} className={"flex items-center gap-1 max-w-full"}>
150
- {renderValue ? renderValue(v, i) : v}
151
- </div>))
152
- : (typeof value === "string" ? (renderValue ? renderValue(value, 0) : value) : placeholder))}
153
-
154
- {renderValues && (!value || Array.isArray(value))
155
- ? renderValues(value as string[] ?? [])
156
- : null}
157
-
158
- {!renderValue && !renderValues && value}
159
-
160
- </SelectPrimitive.Value>
122
+ )}
123
+
124
+ onClick={(e) => {
125
+ e.preventDefault();
126
+ e.stopPropagation();
127
+ }}
128
+ >
129
+ <div
130
+ ref={ref}
131
+ className={cls(
132
+ "flex-grow w-full max-w-full flex flex-row gap-2 items-center",
133
+ "overflow-visible",
134
+ size === "small" ? "h-[42px]" : "h-[64px]"
135
+ )}
136
+ >
137
+ <SelectPrimitive.Value
138
+ onClick={(e) => {
139
+ e.preventDefault();
140
+ e.stopPropagation();
141
+ }}
142
+ placeholder={placeholder}
143
+ className={"w-full"}>
144
+ {hasValue && value && renderValue ? renderValue(value) : placeholder}
145
+ {hasValue && !renderValue && value}
146
+ </SelectPrimitive.Value>
161
147
  </div>
162
-
163
- <SelectPrimitive.Icon className={cn(
164
- "px-2 h-full flex items-center",
165
- )}>
166
- <ExpandMoreIcon size={"small"}
167
- className={cn("transition", open ? "rotate-180" : "")}/>
148
+ <SelectPrimitive.Icon className={cls("px-2 h-full flex items-center")}>
149
+ <ExpandMoreIcon size={"small"} className={cls("transition", open ? "rotate-180" : "")}/>
168
150
  </SelectPrimitive.Icon>
169
-
170
151
  </SelectPrimitive.Trigger>
171
-
172
- {endAdornment && <div className={cn("absolute h-full flex items-center",
173
- size === "small" ? "right-10" : "right-14")}
174
- onClick={(e) => e.stopPropagation()}>
175
- {endAdornment}
176
- </div>}
177
-
152
+ {endAdornment && (
153
+ <div
154
+ className={cls("absolute h-full flex items-center", size === "small" ? "right-10" : "right-14")}
155
+ onClick={(e) => {
156
+ e.preventDefault();
157
+ e.stopPropagation();
158
+ }}>
159
+ {endAdornment}
160
+ </div>
161
+ )}
178
162
  </div>
179
163
  <SelectPrimitive.Portal>
180
- <SelectPrimitive.Content
181
- position={position}
182
- className="z-50 relative overflow-hidden border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-800 p-2 rounded-lg shadow-lg">
183
- <SelectPrimitive.Viewport
184
- className={"p-1"}
185
- style={{
186
- maxHeight: "var(--radix-select-content-available-height)"
187
- }}>
164
+ <SelectPrimitive.Content position={position}
165
+ className={cls(focusedDisabled, "z-50 relative overflow-hidden border bg-white dark:bg-gray-900 p-2 rounded-lg", defaultBorderMixin)}>
166
+ <SelectPrimitive.Viewport className={"p-1"}
167
+ style={{ maxHeight: "var(--radix-select-content-available-height)" }}>
188
168
  {children}
189
169
  </SelectPrimitive.Viewport>
190
170
  </SelectPrimitive.Content>
191
171
  </SelectPrimitive.Portal>
192
172
  </SelectPrimitive.Root>
193
173
  );
194
- }
174
+ });
175
+
176
+ Select.displayName = "Select";
195
177
 
196
178
  export type SelectItemProps = {
197
179
  value: string,
@@ -214,19 +196,17 @@ export function SelectItem({
214
196
  e.preventDefault();
215
197
  e.stopPropagation();
216
198
  }}
217
- className={cn(
199
+ className={cls(
218
200
  "w-full",
219
- "relative relative flex items-center p-2 rounded-md text-sm text-slate-700 dark:text-slate-300",
220
- focusedMixin,
201
+ "relative flex items-center p-2 rounded-md text-sm text-slate-700 dark:text-slate-300",
221
202
  "focus:z-10",
222
- "data-[state=checked]:bg-slate-100 data-[state=checked]:dark:bg-slate-900 focus:bg-slate-100 dark:focus:bg-slate-950",
223
- "data-[state=checked]:focus:bg-slate-200 data-[state=checked]:dark:focus:bg-slate-950",
203
+ "data-[state=checked]:bg-slate-100 data-[state=checked]:dark:bg-slate-800 focus:bg-slate-100 dark:focus:bg-gray-950",
204
+ "data-[state=checked]:focus:bg-slate-200 data-[state=checked]:dark:focus:bg-gray-950",
224
205
  disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
225
206
  "[&>*]:w-full",
226
207
  "overflow-visible",
227
208
  className
228
- )}
229
- >
209
+ )}>
230
210
  <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
231
211
  <div
232
212
  className="absolute left-1 data-[state=checked]:block hidden">
@@ -248,7 +228,7 @@ export function SelectGroup({
248
228
  }: SelectGroupProps) {
249
229
  return <>
250
230
  <SelectPrimitive.Group
251
- className={cn(
231
+ className={cls(
252
232
  "text-xs text-slate-900 dark:text-white uppercase tracking-wider font-bold mt-6 first:mt-2",
253
233
  "px-2 py-2",
254
234
  className
@@ -1,20 +1,26 @@
1
1
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
2
+ import { cls } from "../util";
2
3
 
3
- export function Separator({ orientation, decorative }: {
4
+ export function Separator({
5
+ orientation,
6
+ decorative,
7
+ className
8
+ }: {
4
9
  orientation: "horizontal" | "vertical",
5
- decorative?: boolean
10
+ decorative?: boolean,
11
+ className?: string
6
12
  }) {
7
13
  if (orientation === "horizontal")
8
14
  return (
9
15
  <SeparatorPrimitive.Root
10
16
  decorative={decorative}
11
17
  orientation="horizontal"
12
- className="dark:bg-opacity-50 bg-opacity-50 dark:bg-gray-600 bg-gray-300 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px my-[8px]"/>
18
+ className={cls("dark:bg-opacity-80 dark:bg-gray-800 bg-gray-100 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px my-4", className)}/>
13
19
  );
14
20
  else
15
21
  return (
16
22
  <SeparatorPrimitive.Root
17
- className="dark:bg-opacity-50 bg-opacity-50 dark:bg-gray-600 bg-gray-300 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px mx-[8px]"
23
+ className={cls("dark:bg-opacity-80 dark:bg-gray-800 bg-gray-100 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px mx-4", className)}
18
24
  decorative={decorative}
19
25
  orientation="vertical"
20
26
  />
@@ -1,37 +1,38 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useEffect, useState } from "react";
2
+ import { cls } from "../util";
3
+ import { defaultBorderMixin } from "../styles";
2
4
  import * as DialogPrimitive from "@radix-ui/react-dialog";
3
- import { cn } from "../util";
4
5
 
5
6
  interface SheetProps {
6
7
  children: React.ReactNode;
7
8
  open: boolean;
9
+ title?: string;
8
10
  side?: "top" | "bottom" | "left" | "right";
11
+ darkBackground?: boolean;
9
12
  transparent?: boolean;
10
13
  onOpenChange?: (open: boolean) => void;
14
+ className?: string;
15
+ overlayClassName?: string;
11
16
  }
12
17
 
13
18
  export const Sheet: React.FC<SheetProps> = ({
14
19
  children,
15
20
  side = "right",
21
+ title,
16
22
  open,
17
23
  onOpenChange,
18
24
  transparent,
25
+ className,
26
+ overlayClassName,
19
27
  ...props
20
28
  }) => {
21
-
22
- const [displayed, setDisplayed] = React.useState(false);
29
+ const [displayed, setDisplayed] = useState(false);
23
30
 
24
31
  useEffect(() => {
25
- if (!open) {
26
- const timeout = setTimeout(() => {
27
- setDisplayed(false);
28
- }, 250);
29
- return () => clearTimeout(timeout);
30
- } else {
31
- setDisplayed(true);
32
- return () => {
33
- };
34
- }
32
+ const timeout = setTimeout(() => {
33
+ setDisplayed(open);
34
+ }, 1);
35
+ return () => clearTimeout(timeout);
35
36
  }, [open]);
36
37
 
37
38
  const transformValue: Record<string, string> = {
@@ -41,36 +42,52 @@ export const Sheet: React.FC<SheetProps> = ({
41
42
  right: "translate-x-full"
42
43
  };
43
44
 
44
- return (
45
+ const borderClass: Record<string, string> = {
46
+ top: "border-b",
47
+ bottom: "border-t",
48
+ left: "border-r",
49
+ right: "border-l"
50
+ };
45
51
 
52
+ return (
46
53
  <DialogPrimitive.Root open={displayed || open}
47
54
  onOpenChange={onOpenChange}>
48
55
  <DialogPrimitive.Portal>
56
+ <DialogPrimitive.Title autoFocus tabIndex={0}>
57
+ {title ?? "Sheet"}
58
+ </DialogPrimitive.Title>
49
59
  <DialogPrimitive.Overlay
50
- className={cn(
51
- "fixed inset-0 transition-opacity z-20 ease-in-out duration-200 backdrop-blur-sm",
52
- transparent ? "bg-white bg-opacity-80" : "bg-black bg-opacity-50",
53
- "dark:bg-black dark:bg-opacity-60",
54
- displayed && open ? "opacity-100" : "opacity-0"
60
+ className={cls(
61
+ "fixed inset-0 transition-opacity z-20 ease-in-out duration-100 backdrop-blur-sm",
62
+ "bg-black bg-opacity-50",
63
+ "dark:bg-gray-900 dark:bg-opacity-60",
64
+ displayed && open ? "opacity-100" : "opacity-0",
65
+ overlayClassName
55
66
  )}
56
67
  style={{
57
- pointerEvents: displayed ? "auto" : "none",
68
+ pointerEvents: displayed ? "auto" : "none"
58
69
  }}
70
+ onClick={() => onOpenChange && onOpenChange(false)}
59
71
  />
60
72
  <DialogPrimitive.Content
61
73
  {...props}
62
- className={cn(
63
- // "transform-gpu",
74
+ onFocusCapture={(event) => event.preventDefault()}
75
+ className={cls(
76
+ borderClass[side],
77
+ defaultBorderMixin,
78
+ "transform-gpu",
64
79
  "will-change-transform",
65
80
  "text-slate-900 dark:text-white",
66
- "fixed transform z-20 transition-all duration-[240ms] ease-in-out",
81
+ "fixed transform z-20 transition-all ease-in-out",
82
+ !displayed ? "duration-150" : "duration-100",
67
83
  "outline-none focus:outline-none",
68
- !transparent ? "shadow-md" : "",
84
+ transparent ? "" : "shadow-md bg-white dark:bg-gray-950",
69
85
  side === "top" || side === "bottom" ? "w-full" : "h-full",
70
86
  side === "left" || side === "top" ? "left-0 top-0" : "right-0 bottom-0",
71
- displayed && open ? "opacity-100" : "opacity-0",
72
- !displayed || !open ? transformValue[side] : "")
73
- }
87
+ displayed && open ? "opacity-100" : "opacity-50",
88
+ !displayed || !open ? transformValue[side] : "",
89
+ className
90
+ )}
74
91
  >
75
92
  {children}
76
93
  </DialogPrimitive.Content>
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { cn } from "../util";
2
+ import { cls } from "../util";
3
3
 
4
4
  export type SkeletonProps = {
5
5
  width?: number;
@@ -12,13 +12,16 @@ export function Skeleton({
12
12
  height,
13
13
  className
14
14
  }: SkeletonProps) {
15
- return <span className={
16
- cn(
15
+ return <span
16
+ style={{
17
+ width: width ? `${width}px` : "100%",
18
+ height: height ? `${height}px` : "12px"
19
+ }}
20
+ className={
21
+ cls(
17
22
  "block",
18
- "bg-slate-200 dark:bg-slate-800 rounded",
23
+ "bg-slate-200 dark:bg-slate-800 rounded-md",
19
24
  "animate-pulse",
20
- width ? `w-[${width}px]` : "w-full",
21
- height ? `h-[${height}px]` : "h-3",
22
25
  "max-w-full max-h-full",
23
26
  className)
24
27
  }/>;