@blenx-dev/core 0.1.0 → 0.2.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 (58) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/iconify.config.ts +23 -0
  3. package/package.json +17 -7
  4. package/scripts/generate-icons.ts +82 -0
  5. package/src/components/Accordion/accordion.tsx +2 -2
  6. package/src/components/Autocomplete/autocomplete.tsx +2 -2
  7. package/src/components/Breadcrumbs/breadcrumbs.tsx +3 -3
  8. package/src/components/Checkbox/checkbox.tsx +2 -15
  9. package/src/components/CloseButton/close-button.tsx +2 -5
  10. package/src/components/Combobox/combobox.tsx +5 -5
  11. package/src/components/Command/command.tsx +2 -2
  12. package/src/components/CopyButton/copy-button.tsx +3 -11
  13. package/src/components/Drawer/drawer.tsx +3 -29
  14. package/src/components/Icon/icon.tsx +3 -3
  15. package/src/components/Popover/popover.tsx +24 -14
  16. package/src/components/Select/select.tsx +5 -5
  17. package/src/components/Spinner/spinner.tsx +3 -5
  18. package/src/components/Stack/stack.tsx +5 -15
  19. package/src/components/Text/text.tsx +1 -1
  20. package/src/components/index.ts +0 -3
  21. package/src/icons/ArrowRightIcon.tsx +20 -0
  22. package/src/icons/CalendarIcon.tsx +20 -0
  23. package/src/icons/CheckIcon.tsx +20 -0
  24. package/src/icons/ChevronDownIcon.tsx +20 -0
  25. package/src/icons/ChevronLeftIcon.tsx +20 -0
  26. package/src/icons/ChevronRightIcon.tsx +20 -0
  27. package/src/icons/ChevronUpIcon.tsx +20 -0
  28. package/src/icons/CircleAlertIcon.tsx +20 -0
  29. package/src/icons/CopyIcon.tsx +20 -0
  30. package/src/icons/EllipsisIcon.tsx +20 -0
  31. package/src/icons/FolderOpenIcon.tsx +20 -0
  32. package/src/icons/ListIcon.tsx +20 -0
  33. package/src/icons/LoaderCircleIcon.tsx +20 -0
  34. package/src/icons/SearchIcon.tsx +20 -0
  35. package/src/icons/SquareCheckIcon.tsx +20 -0
  36. package/src/icons/XIcon.tsx +20 -0
  37. package/src/icons/index.ts +17 -0
  38. package/src/utils/sprinkles.css.ts +18 -4
  39. package/src/DataTable/data-table-column-toggle.tsx +0 -73
  40. package/src/DataTable/data-table-empty.tsx +0 -27
  41. package/src/DataTable/data-table-error.tsx +0 -25
  42. package/src/DataTable/data-table-infinite-loader.tsx +0 -73
  43. package/src/DataTable/data-table-loading.tsx +0 -67
  44. package/src/DataTable/data-table-pagination.tsx +0 -80
  45. package/src/DataTable/data-table-toolbar.tsx +0 -62
  46. package/src/DataTable/data-table.css.ts +0 -420
  47. package/src/DataTable/data-table.tsx +0 -507
  48. package/src/DataTable/index.ts +0 -24
  49. package/src/DataTable/types.ts +0 -169
  50. package/src/DataTable/use-infinite-scroll.ts +0 -67
  51. package/src/components/Calendar/calendar.css.ts +0 -187
  52. package/src/components/Calendar/calendar.tsx +0 -143
  53. package/src/components/Calendar/index.ts +0 -1
  54. package/src/components/ColorPicker/color-picker.tsx +0 -123
  55. package/src/components/ColorPicker/index.ts +0 -1
  56. package/src/components/DatePicker/date-picker.tsx +0 -75
  57. package/src/components/DatePicker/index.ts +0 -1
  58. package/src/components/Stack/stack.css.ts +0 -42
@@ -1,67 +0,0 @@
1
- import { Spinner } from "../components";
2
- import type { TableSize } from "./types";
3
- import * as styles from "./data-table.css";
4
-
5
- interface DataTableLoadingProps {
6
- rowCount?: number;
7
- columnCount?: number;
8
- size?: TableSize;
9
- }
10
-
11
- const ROW_HEIGHTS: Record<TableSize, number> = {
12
- sm: 36,
13
- md: 48,
14
- lg: 60,
15
- };
16
-
17
- export function DataTableLoading({
18
- rowCount = 5,
19
- columnCount = 4,
20
- size = "md",
21
- }: DataTableLoadingProps) {
22
- const rowHeight = ROW_HEIGHTS[size];
23
-
24
- return (
25
- <output className={styles.loadingWrapper} aria-label="Loading table data">
26
- <table className={styles.loadingTable}>
27
- <thead>
28
- <tr>
29
- {Array.from({ length: columnCount }).map((_, i) => (
30
- <th key={`skeleton-header-${i.toString()}`} className={styles.headerCell}>
31
- <div
32
- className={styles.skeletonBar}
33
- style={{ height: 14, width: `${60 + ((i * 10) % 40)}px` }}
34
- />
35
- </th>
36
- ))}
37
- </tr>
38
- </thead>
39
- <tbody>
40
- {Array.from({ length: rowCount }).map((_unknown, rowIdx) => (
41
- <tr key={`skeleton-row-${rowIdx.toString()}`}>
42
- {Array.from({ length: columnCount }).map((_, colIdx) => (
43
- <td
44
- key={`skeleton-cell-${rowIdx.toString()}-${colIdx.toString()}`}
45
- className={styles.cell}
46
- style={{ height: rowHeight }}
47
- >
48
- <div
49
- className={styles.skeletonBar}
50
- style={{
51
- height: 12,
52
- width: `${80 + ((rowIdx * 7 + colIdx * 13) % 20)}%`,
53
- }}
54
- />
55
- </td>
56
- ))}
57
- </tr>
58
- ))}
59
- </tbody>
60
- </table>
61
- <div className={styles.loadingFooter}>
62
- <Spinner />
63
- <span className={styles.loadingText}>Loading data...</span>
64
- </div>
65
- </output>
66
- );
67
- }
@@ -1,80 +0,0 @@
1
- import { Button } from "../components";
2
- import { CaretLeftIcon, CaretRightIcon } from "@phosphor-icons/react";
3
- import type { Table } from "@tanstack/react-table";
4
- import * as styles from "./data-table.css";
5
-
6
- interface DataTablePaginationProps<TData> {
7
- table: Table<TData>;
8
- }
9
-
10
- export function DataTablePagination<TData>({ table }: DataTablePaginationProps<TData>) {
11
- const { pageIndex } = table.getState().pagination;
12
- const pageCount = table.getPageCount();
13
- const totalRows = table.getPrePaginationRowModel().rows.length;
14
- const { pageSize } = table.getState().pagination;
15
- const startRow = pageIndex * pageSize + 1;
16
- const endRow = Math.min((pageIndex + 1) * pageSize, totalRows);
17
- const canPreviousPage = table.getCanPreviousPage();
18
- const canNextPage = table.getCanNextPage();
19
-
20
- return (
21
- <nav aria-label="Pagination" className={styles.nav}>
22
- <span className={styles.info}>{totalRows} results</span>
23
- <div className={styles.controls}>
24
- <span className={styles.range}>
25
- {startRow}-{endRow} of {totalRows}
26
- </span>
27
- <div className={styles.buttonGroup}>
28
- <Button
29
- variant="outline"
30
- size="sm"
31
- disabled={!canPreviousPage}
32
- onClick={() => table.previousPage()}
33
- aria-label="Previous page"
34
- >
35
- <CaretLeftIcon size={16} />
36
- </Button>
37
- {Array.from({ length: pageCount }, (_, i) => i + 1)
38
- .filter((page) => {
39
- const current = pageIndex + 1;
40
- if (pageCount <= 7) return true;
41
- if (page === 1 || page === pageCount) return true;
42
- if (Math.abs(page - current) <= 1) return true;
43
- return false;
44
- })
45
- .map((page, idx, filtered) => {
46
- const pageIdx = page - 1;
47
- const isActive = pageIdx === pageIndex;
48
- const showGap = idx > 0 && page - filtered[idx - 1]! > 1;
49
- return (
50
- <div key={`page-${page.toString()}`} className={styles.pageWrap}>
51
- {showGap && <span className={styles.ellipsis}>...</span>}
52
- <Button
53
- variant={isActive ? "solid" : "ghost"}
54
- intent={isActive ? "primary" : undefined}
55
- size="sm"
56
- disabled={isActive}
57
- onClick={() => table.setPageIndex(pageIdx)}
58
- aria-label={`Page ${page.toString()}`}
59
- aria-current={isActive ? "page" : undefined}
60
- className={styles.pageButton}
61
- >
62
- {page.toString()}
63
- </Button>
64
- </div>
65
- );
66
- })}
67
- <Button
68
- variant="outline"
69
- size="sm"
70
- disabled={!canNextPage}
71
- onClick={() => table.nextPage()}
72
- aria-label="Next page"
73
- >
74
- <CaretRightIcon size={16} />
75
- </Button>
76
- </div>
77
- </div>
78
- </nav>
79
- );
80
- }
@@ -1,62 +0,0 @@
1
- import { Button, Input } from "../components";
2
- import type { Table } from "@tanstack/react-table";
3
- import { DataTableColumnToggle } from "./data-table-column-toggle";
4
- import type { BulkAction, TableFeatures } from "./types";
5
- import * as styles from "./data-table.css";
6
-
7
- interface DataTableToolbarProps<TData> {
8
- table: Table<TData>;
9
- features?: TableFeatures;
10
- globalSearch?: string;
11
- onGlobalSearchChange?: (value: string) => void;
12
- customToolbar?: React.ReactNode;
13
- bulkActions?: BulkAction<TData>[];
14
- selectedRows: TData[];
15
- }
16
-
17
- export function DataTableToolbar<TData>({
18
- table,
19
- features,
20
- globalSearch,
21
- onGlobalSearchChange,
22
- customToolbar,
23
- bulkActions,
24
- selectedRows,
25
- }: DataTableToolbarProps<TData>) {
26
- return (
27
- <div className={styles.toolbarContainer}>
28
- <div className={styles.leftGroup}>
29
- {features?.globalSearch && (
30
- <div className={styles.searchWrap}>
31
- <Input
32
- size="sm"
33
- placeholder="Search..."
34
- value={globalSearch ?? ""}
35
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
36
- onGlobalSearchChange?.(e.target.value);
37
- }}
38
- />
39
- </div>
40
- )}
41
- {selectedRows.length > 0 &&
42
- bulkActions?.map((action, index) => (
43
- <Button
44
- key={`bulk-action-${index.toString()}`}
45
- variant={action.variant === "destructive" ? "solid" : "outline"}
46
- intent={action.variant === "destructive" ? "danger" : undefined}
47
- size="sm"
48
- disabled={action.disabled}
49
- onClick={() => action.onClick(selectedRows)}
50
- >
51
- {action.icon && <span>{action.icon}</span>}
52
- {action.label}
53
- </Button>
54
- ))}
55
- </div>
56
- <div className={styles.rightGroup}>
57
- {customToolbar}
58
- {features?.columnVisibility && <DataTableColumnToggle table={table} />}
59
- </div>
60
- </div>
61
- );
62
- }
@@ -1,420 +0,0 @@
1
- import { style, keyframes } from "@vanilla-extract/css";
2
- import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
-
4
- const pulse = keyframes({
5
- "0%, 100%": { opacity: 0.4 },
6
- "50%": { opacity: 0.8 },
7
- });
8
-
9
- export const actionsCell = style({
10
- display: "flex",
11
- gap: 4,
12
- });
13
-
14
- export const checkbox = style({
15
- cursor: "pointer",
16
- });
17
-
18
- export const fetchingBar = style({
19
- display: "flex",
20
- justifyContent: "center",
21
- alignItems: "center",
22
- padding: tokenVars.spacing.sm,
23
- gap: tokenVars.spacing.sm,
24
- });
25
-
26
- export const fetchingText = style({
27
- color: semanticVars.text.secondary,
28
- fontSize: "13px",
29
- });
30
-
31
- export const tableContainer = style({
32
- overflowX: "auto",
33
- overflowY: "auto",
34
- borderRadius: tokenVars.borderRadius.md,
35
- borderWidth: 1,
36
- borderStyle: "solid",
37
- borderColor: semanticVars.border.default,
38
- position: "relative",
39
- });
40
-
41
- export const table = style({
42
- width: "100%",
43
- borderCollapse: "collapse",
44
- tableLayout: "auto",
45
- });
46
-
47
- export const theadStatic = style({});
48
-
49
- export const theadSticky = style({
50
- position: "sticky",
51
- top: 0,
52
- zIndex: 1,
53
- });
54
-
55
- export const theadStickyScrolled = style({
56
- position: "sticky",
57
- top: 0,
58
- zIndex: 1,
59
- boxShadow: tokenVars.shadow.sm,
60
- });
61
-
62
- export const headRow = style({
63
- backgroundColor: semanticVars.background.subtle,
64
- });
65
-
66
- export const th = style({
67
- paddingTop: 10,
68
- paddingBottom: 10,
69
- paddingLeft: 12,
70
- paddingRight: 12,
71
- fontSize: "12px",
72
- fontWeight: tokenVars.fontWeight.semibold,
73
- color: semanticVars.text.secondary,
74
- textAlign: "left",
75
- textTransform: "uppercase",
76
- letterSpacing: "0.05em",
77
- borderBottomWidth: 1,
78
- borderBottomStyle: "solid",
79
- borderBottomColor: semanticVars.border.default,
80
- whiteSpace: "nowrap",
81
- userSelect: "none",
82
- });
83
-
84
- export const thSm = style({
85
- fontSize: "11px",
86
- paddingTop: 6,
87
- paddingBottom: 6,
88
- paddingLeft: 8,
89
- paddingRight: 8,
90
- });
91
-
92
- export const thLg = style({
93
- fontSize: "13px",
94
- paddingTop: 14,
95
- paddingBottom: 14,
96
- paddingLeft: 16,
97
- paddingRight: 16,
98
- });
99
-
100
- export const thSortable = style({
101
- cursor: "pointer",
102
- });
103
-
104
- export const thContent = style({
105
- display: "flex",
106
- alignItems: "center",
107
- gap: 4,
108
- });
109
-
110
- export const td = style({
111
- paddingTop: 10,
112
- paddingBottom: 10,
113
- paddingLeft: 12,
114
- paddingRight: 12,
115
- fontSize: tokenVars.fontSize.sm,
116
- color: semanticVars.text.primary,
117
- borderBottomWidth: 1,
118
- borderBottomStyle: "solid",
119
- borderBottomColor: semanticVars.border.subtle,
120
- whiteSpace: "nowrap",
121
- overflow: "hidden",
122
- textOverflow: "ellipsis",
123
- });
124
-
125
- export const tdSm = style({
126
- paddingTop: 6,
127
- paddingBottom: 6,
128
- paddingLeft: 8,
129
- paddingRight: 8,
130
- });
131
-
132
- export const tdLg = style({
133
- paddingTop: 14,
134
- paddingBottom: 14,
135
- paddingLeft: 16,
136
- paddingRight: 16,
137
- });
138
-
139
- export const tr = style({
140
- transition: "background-color 0.15s ease",
141
- });
142
-
143
- export const trSm = style({ height: 36 });
144
-
145
- export const trLg = style({ height: 60 });
146
-
147
- export const trSelected = style({
148
- backgroundColor: semanticVars.background.subtle,
149
- });
150
-
151
- export const emptyTd = style({
152
- padding: 0,
153
- borderBottomWidth: 1,
154
- borderBottomStyle: "solid",
155
- borderBottomColor: semanticVars.border.default,
156
- });
157
-
158
- // ─── Loading skeleton ────────────────────────────────────────────────────────
159
-
160
- export const loadingWrapper = style({
161
- width: "100%",
162
- });
163
-
164
- export const loadingTable = style({
165
- width: "100%",
166
- borderCollapse: "collapse",
167
- });
168
-
169
- export const headerCell = style({
170
- paddingTop: 12,
171
- paddingBottom: 12,
172
- paddingLeft: 16,
173
- paddingRight: 16,
174
- borderBottomColor: semanticVars.border.default,
175
- borderBottomStyle: "solid",
176
- borderBottomWidth: 1,
177
- });
178
-
179
- export const skeletonBar = style({
180
- borderRadius: 4,
181
- backgroundColor: semanticVars.surface.raised,
182
- animationName: pulse,
183
- animationDuration: "1.5s",
184
- animationTimingFunction: "ease-in-out",
185
- animationIterationCount: "infinite",
186
- });
187
-
188
- export const cell = style({
189
- paddingTop: 12,
190
- paddingBottom: 12,
191
- paddingLeft: 16,
192
- paddingRight: 16,
193
- borderBottomColor: semanticVars.border.subtle,
194
- borderBottomStyle: "solid",
195
- borderBottomWidth: 1,
196
- });
197
-
198
- export const loadingFooter = style({
199
- display: "flex",
200
- justifyContent: "center",
201
- alignItems: "center",
202
- padding: 16,
203
- gap: 8,
204
- });
205
-
206
- export const loadingText = style({
207
- color: semanticVars.text.secondary,
208
- fontSize: tokenVars.fontSize.sm,
209
- });
210
-
211
- // ─── Column toggle ───────────────────────────────────────────────────────────
212
-
213
- export const itemLabel = style({
214
- fontSize: 14,
215
- });
216
-
217
- export const deselectLabel = style({
218
- color: semanticVars.text.secondary,
219
- fontSize: 13,
220
- });
221
-
222
- export const checkboxChecked = style({
223
- marginLeft: "auto",
224
- width: 16,
225
- height: 16,
226
- borderRadius: 3,
227
- borderWidth: 1.5,
228
- borderStyle: "solid",
229
- borderColor: semanticVars.interactive.primary,
230
- display: "inline-flex",
231
- alignItems: "center",
232
- justifyContent: "center",
233
- backgroundColor: semanticVars.interactive.primary,
234
- });
235
-
236
- export const checkboxUnchecked = style({
237
- marginLeft: "auto",
238
- width: 16,
239
- height: 16,
240
- borderRadius: 3,
241
- borderWidth: 1.5,
242
- borderStyle: "solid",
243
- borderColor: semanticVars.border.default,
244
- display: "inline-flex",
245
- alignItems: "center",
246
- justifyContent: "center",
247
- backgroundColor: "transparent",
248
- });
249
-
250
- export const partial = style({
251
- width: 8,
252
- height: 2,
253
- borderRadius: 1,
254
- backgroundColor: semanticVars.text.secondary,
255
- });
256
-
257
- // ─── Empty state ─────────────────────────────────────────────────────────────
258
-
259
- export const emptyContainer = style({
260
- display: "flex",
261
- flexDirection: "column",
262
- alignItems: "center",
263
- justifyContent: "center",
264
- paddingTop: tokenVars.spacing.xxxl,
265
- paddingBottom: tokenVars.spacing.xxxl,
266
- paddingLeft: tokenVars.spacing.md,
267
- paddingRight: tokenVars.spacing.md,
268
- gap: 12,
269
- });
270
-
271
- export const iconWrap = style({
272
- opacity: 0.5,
273
- });
274
-
275
- export const message = style({
276
- color: semanticVars.text.secondary,
277
- fontSize: tokenVars.fontSize.sm,
278
- lineHeight: 1.5,
279
- textAlign: "center",
280
- margin: 0,
281
- });
282
-
283
- export const actionWrap = style({
284
- marginTop: tokenVars.spacing.xs,
285
- });
286
-
287
- // ─── Error state ─────────────────────────────────────────────────────────────
288
-
289
- export const errorContainer = style({
290
- display: "flex",
291
- flexDirection: "column",
292
- alignItems: "center",
293
- justifyContent: "center",
294
- paddingTop: tokenVars.spacing.xxxl,
295
- paddingBottom: tokenVars.spacing.xxxl,
296
- paddingLeft: tokenVars.spacing.md,
297
- paddingRight: tokenVars.spacing.md,
298
- gap: 12,
299
- });
300
-
301
- export const errorMessage = style({
302
- color: semanticVars.status.danger,
303
- fontSize: tokenVars.fontSize.sm,
304
- lineHeight: 1.5,
305
- textAlign: "center",
306
- margin: 0,
307
- });
308
-
309
- // ─── Infinite loader ─────────────────────────────────────────────────────────
310
-
311
- export const sentinel = style({
312
- display: "flex",
313
- justifyContent: "center",
314
- alignItems: "center",
315
- padding: tokenVars.spacing.md,
316
- minHeight: 48,
317
- });
318
-
319
- export const loadingInline = style({
320
- display: "flex",
321
- alignItems: "center",
322
- gap: tokenVars.spacing.sm,
323
- });
324
-
325
- export const loaderLoadingText = style({
326
- color: semanticVars.text.secondary,
327
- fontSize: tokenVars.fontSize.sm,
328
- });
329
-
330
- export const noMore = style({
331
- color: semanticVars.text.disabled,
332
- fontSize: tokenVars.fontSize.sm,
333
- });
334
-
335
- export const center = style({
336
- display: "flex",
337
- justifyContent: "center",
338
- alignItems: "center",
339
- padding: tokenVars.spacing.md,
340
- });
341
-
342
- // ─── Pagination ──────────────────────────────────────────────────────────────
343
-
344
- export const nav = style({
345
- display: "flex",
346
- alignItems: "center",
347
- justifyContent: "space-between",
348
- paddingTop: tokenVars.spacing.sm,
349
- paddingBottom: tokenVars.spacing.sm,
350
- });
351
-
352
- export const info = style({
353
- color: semanticVars.text.secondary,
354
- fontSize: tokenVars.fontSize.sm,
355
- });
356
-
357
- export const controls = style({
358
- display: "flex",
359
- alignItems: "center",
360
- gap: tokenVars.spacing.sm,
361
- });
362
-
363
- export const range = style({
364
- color: semanticVars.text.secondary,
365
- fontSize: tokenVars.fontSize.sm,
366
- whiteSpace: "nowrap",
367
- });
368
-
369
- export const buttonGroup = style({
370
- display: "flex",
371
- alignItems: "center",
372
- gap: tokenVars.spacing.xs,
373
- });
374
-
375
- export const pageWrap = style({
376
- display: "flex",
377
- alignItems: "center",
378
- gap: 2,
379
- });
380
-
381
- export const ellipsis = style({
382
- color: semanticVars.text.disabled,
383
- fontSize: tokenVars.fontSize.sm,
384
- paddingLeft: tokenVars.spacing.xs,
385
- paddingRight: tokenVars.spacing.xs,
386
- });
387
-
388
- export const pageButton = style({
389
- minWidth: 32,
390
- height: 32,
391
- });
392
-
393
- // ─── Toolbar ─────────────────────────────────────────────────────────────────
394
-
395
- export const toolbarContainer = style({
396
- display: "flex",
397
- alignItems: "center",
398
- justifyContent: "space-between",
399
- gap: tokenVars.spacing.md,
400
- paddingTop: tokenVars.spacing.sm,
401
- paddingBottom: tokenVars.spacing.sm,
402
- });
403
-
404
- export const leftGroup = style({
405
- display: "flex",
406
- alignItems: "center",
407
- gap: tokenVars.spacing.sm,
408
- flex: 1,
409
- });
410
-
411
- export const rightGroup = style({
412
- display: "flex",
413
- alignItems: "center",
414
- gap: tokenVars.spacing.sm,
415
- });
416
-
417
- export const searchWrap = style({
418
- flex: 1,
419
- maxWidth: 320,
420
- });