notionsoft-ui 1.0.40 → 1.0.42

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notionsoft-ui",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "A React UI component installer (shadcn-style). Installs components directly into your project.",
5
5
  "bin": {
6
6
  "notionsoft-ui": "./cli/index.cjs"
@@ -31,7 +31,10 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
31
31
  return (
32
32
  <div
33
33
  data-slot="card-title"
34
- className={cn("leading-none font-semibold", className)}
34
+ className={cn(
35
+ "leading-none ltr:text-md rtl:text-md font-semibold",
36
+ className
37
+ )}
35
38
  {...props}
36
39
  />
37
40
  );
@@ -41,7 +44,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
41
44
  return (
42
45
  <div
43
46
  data-slot="card-description"
44
- className={cn("text-muted-foreground text-sm", className)}
47
+ className={cn("text-muted-foreground ltr:text-sm rtl:text-md", className)}
45
48
  {...props}
46
49
  />
47
50
  );
@@ -0,0 +1,74 @@
1
+ import CircleLoader from "@/components/notion-ui/circle-loader";
2
+ import { cn } from "@/utils/cn";
3
+ import { CheckIcon } from "lucide-react";
4
+ import React from "react";
5
+
6
+ export interface CheckboxProps
7
+ extends React.InputHTMLAttributes<HTMLInputElement> {
8
+ onCheckedChange: (value: boolean) => void;
9
+ checked: boolean;
10
+ loading?: boolean;
11
+ label?: string;
12
+ description?: string;
13
+ classNames?: {
14
+ rootDivClassName?: string;
15
+ };
16
+ }
17
+ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
18
+ (props, ref: any) => {
19
+ const {
20
+ onCheckedChange,
21
+ checked,
22
+ loading,
23
+ label,
24
+ description,
25
+ className,
26
+ readOnly,
27
+ classNames,
28
+ } = props;
29
+ const { rootDivClassName } = classNames || {};
30
+
31
+ const readOnlyStyle = readOnly && "opacity-40";
32
+
33
+ return (
34
+ <div
35
+ className={cn(
36
+ "flex items-center space-x-3",
37
+ rootDivClassName,
38
+ readOnlyStyle
39
+ )}
40
+ >
41
+ {loading ? (
42
+ <CircleLoader className="size-4" />
43
+ ) : (
44
+ <label className="inline-flex items-center">
45
+ <input
46
+ ref={ref}
47
+ type="checkbox"
48
+ checked={checked}
49
+ onChange={(e) => onCheckedChange(e.target.checked)}
50
+ className={cn("peer sr-only", className)}
51
+ />
52
+
53
+ <CheckIcon className="size-4 shadow-sm p-px border border-tertiary/60 text-transparent peer-checked:bg-primary peer-checked:text-primary-foreground transition-transform rounded peer-checked:scale-100" />
54
+ </label>
55
+ )}
56
+
57
+ <label className="text-sm font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
58
+ {label && (
59
+ <h1 className="text-start rtl:text-[18px] ltr:text-[13px] font-semibold">
60
+ {label}
61
+ </h1>
62
+ )}
63
+ {description && (
64
+ <h1 className="text-start rtl:pr-1 rtl:text-[17px] ltr:text-xs pt-0.5 ltr:leading-3.5 rtl:leading-5 text-primary/80">
65
+ {description}
66
+ </h1>
67
+ )}
68
+ </label>
69
+ </div>
70
+ );
71
+ }
72
+ );
73
+
74
+ export default Checkbox;
@@ -88,12 +88,10 @@ const PageSizeSelect: React.FC<SelectProps> = ({
88
88
  const cached = await loadFn(paginationKey);
89
89
  if (cached) {
90
90
  setSelectData((p) => ({ ...p, select: cached }));
91
- onChange?.(cached.value);
92
91
  } else {
93
92
  const item = { key: paginationKey, value: "10", option: KEYS.default };
94
93
  setSelectData((p) => ({ ...p, select: item }));
95
94
  saveFn(paginationKey, item);
96
- onChange?.("10");
97
95
  }
98
96
  };
99
97
  loadCache();
@@ -188,7 +186,7 @@ const PageSizeSelect: React.FC<SelectProps> = ({
188
186
  <div ref={selectRef} className={cn("w-full", className)}>
189
187
  <button
190
188
  onClick={() => setSelectData((p) => ({ ...p, isOpen: !p.isOpen }))}
191
- className="w-full px-3 py-2 border rounded-md flex items-center justify-between bg-card"
189
+ className="w-full gap-1 text-sm px-2 py-2 border rounded-md flex items-center justify-between bg-card"
192
190
  >
193
191
  {selectData.select.value || placeholder}
194
192
  <ChevronDown
@@ -252,16 +250,14 @@ const PageSizeSelect: React.FC<SelectProps> = ({
252
250
  {/* Options */}
253
251
  <ul className="max-h-60 overflow-auto">
254
252
  {options.length === 0 ? (
255
- <li className="px-4 py-2 text-center text-sm">
256
- {emptyPlaceholder}
257
- </li>
253
+ <li className="px-4 py-2 text-center">{emptyPlaceholder}</li>
258
254
  ) : (
259
255
  options.map((o) => (
260
256
  <li
261
257
  key={o.value}
262
258
  onClick={() => handleSelect(o.value)}
263
259
  className={cn(
264
- "px-4 py-2 cursor-pointer flex justify-between hover:bg-primary/10",
260
+ "px-4 py-2 text-sm cursor-pointer flex justify-between hover:bg-primary/10",
265
261
  selectData.select.value === o.value && "bg-primary/10"
266
262
  )}
267
263
  >
@@ -166,9 +166,9 @@ export const SidebarItem = memo(function SidebarItem({
166
166
  <div
167
167
  onClick={handleClick}
168
168
  className={cn(
169
- `grid grid-cols-[1fr_auto] ltr:py-2 rtl:p-1 ltr:pl-2.5 rtl:pr-2 ltr:mx-1 rtl:mx-1.5 text-primary items-center rtl:text-lg ltr:text-xs cursor-pointer rounded-md ${
169
+ `grid grid-cols-[1fr_auto] ltr:py-2 dark:text-primary/70 rtl:p-1 ltr:pl-2.5 rtl:pr-[7px] ltr:mx-1 rtl:mx-1.5 text-primary items-center rtl:text-lg ltr:text-xs cursor-pointer rounded-md ${
170
170
  isActive
171
- ? `bg-tertiary/90 text-card font-semibold`
171
+ ? `bg-tertiary/90 text-card dark:text-primary font-semibold`
172
172
  : "hover:opacity-75"
173
173
  }`
174
174
  )}
@@ -0,0 +1,203 @@
1
+ import CircleLoader from "@/components/notion-ui/circle-loader";
2
+ import { cn } from "@/utils/cn";
3
+ import { Edit, Eye, Trash2 } from "lucide-react";
4
+ import * as React from "react";
5
+
6
+ function Table({ className, ...props }: React.ComponentProps<"table">) {
7
+ return (
8
+ <div
9
+ data-slot="table-container"
10
+ className="relative w-full overflow-x-auto"
11
+ >
12
+ <table
13
+ data-slot="table"
14
+ className={cn("w-full caption-bottom text-sm", className)}
15
+ {...props}
16
+ />
17
+ </div>
18
+ );
19
+ }
20
+
21
+ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
22
+ return (
23
+ <thead
24
+ data-slot="table-header"
25
+ className={cn("[&_tr]:border-b rtl:text-lg ltr:text-sm", className)}
26
+ {...props}
27
+ />
28
+ );
29
+ }
30
+
31
+ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
32
+ return (
33
+ <tbody
34
+ data-slot="table-body"
35
+ className={cn(
36
+ "[&_tr:last-child]:border-0 rtl:text-md ltr:text-xs",
37
+ className
38
+ )}
39
+ {...props}
40
+ />
41
+ );
42
+ }
43
+
44
+ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
45
+ return (
46
+ <tfoot
47
+ data-slot="table-footer"
48
+ className={cn(
49
+ "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ );
55
+ }
56
+
57
+ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
58
+ return (
59
+ <tr
60
+ data-slot="table-row"
61
+ className={cn(
62
+ "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
63
+ className
64
+ )}
65
+ {...props}
66
+ />
67
+ );
68
+ }
69
+
70
+ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
71
+ return (
72
+ <th
73
+ data-slot="table-head"
74
+ className={cn(
75
+ "font-medium text-muted-foreground h-10 px-2 text-left align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-0.5",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
84
+ return (
85
+ <td
86
+ data-slot="table-cell"
87
+ className={cn(
88
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-0.5",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ );
94
+ }
95
+
96
+ function TableCaption({
97
+ className,
98
+ ...props
99
+ }: React.ComponentProps<"caption">) {
100
+ return (
101
+ <caption
102
+ data-slot="table-caption"
103
+ className={cn("text-muted-foreground mt-4 text-sm", className)}
104
+ {...props}
105
+ />
106
+ );
107
+ }
108
+
109
+ interface TableRowIconProps extends React.HTMLAttributes<HTMLTableRowElement> {
110
+ read?: boolean;
111
+ remove?: boolean;
112
+ edit?: boolean;
113
+ onRemove: (item: any) => Promise<void>;
114
+ onEdit: (item: any) => Promise<void>;
115
+ onRead: (item: any) => Promise<void>;
116
+ item: any;
117
+ }
118
+ const TableRowIcon = React.forwardRef<HTMLTableRowElement, TableRowIconProps>(
119
+ (
120
+ { className, read, edit, remove, onRemove, onEdit, onRead, item, ...props },
121
+ ref
122
+ ) => {
123
+ const { children } = props;
124
+ const [showAction, setShowAction] = React.useState(false);
125
+ const [loading, setLoading] = React.useState(false);
126
+ return (
127
+ <TableRow
128
+ className={cn(`${showAction && "bg-primary/10!"} relative`, className)}
129
+ {...props}
130
+ ref={ref}
131
+ onMouseEnter={() => {
132
+ if (read || edit || remove) setShowAction(true);
133
+ }}
134
+ onMouseLeave={() => setShowAction(false)}
135
+ >
136
+ {children}
137
+ <td>
138
+ {showAction && (
139
+ <div className="w-[110px] bg-primary py-1 rounded-full flex absolute top-1/2 transform -translate-y-1/2 ltr:right-2 rtl:left-2 justify-center gap-x-2">
140
+ {read && !edit && (
141
+ <div
142
+ onClick={async () => {
143
+ if (loading) return;
144
+ setLoading(true);
145
+ await onRead(item);
146
+ setLoading(false);
147
+ }}
148
+ className="cursor-pointer hover:*:text-primary-foreground/70"
149
+ >
150
+ <Eye className="text-primary-foreground size-[18px] transition" />
151
+ </div>
152
+ )}
153
+ {edit && (
154
+ <div
155
+ onClick={async () => {
156
+ if (loading) return;
157
+ setLoading(true);
158
+ await onEdit(item);
159
+ setLoading(false);
160
+ }}
161
+ className="cursor-pointer hover:*:text-green-500/70"
162
+ >
163
+ <Edit className="text-green-500 size-[18px] transition" />
164
+ </div>
165
+ )}
166
+
167
+ {remove && (
168
+ <div
169
+ onClick={async () => {
170
+ if (loading) return;
171
+ setLoading(true);
172
+ await onRemove(item);
173
+ setLoading(false);
174
+ }}
175
+ className="cursor-pointer hover:*:text-red-400/70"
176
+ >
177
+ <Trash2 className="text-red-400 size-[18px] transition" />
178
+ </div>
179
+ )}
180
+ </div>
181
+ )}
182
+ </td>
183
+ {loading && (
184
+ <td className="w-full h-full bg-primary/20 absolute flex justify-center left-0">
185
+ <CircleLoader className="size-[18px]" />
186
+ </td>
187
+ )}
188
+ </TableRow>
189
+ );
190
+ }
191
+ );
192
+
193
+ export {
194
+ Table,
195
+ TableHeader,
196
+ TableBody,
197
+ TableFooter,
198
+ TableHead,
199
+ TableRow,
200
+ TableCell,
201
+ TableCaption,
202
+ TableRowIcon,
203
+ };