shadcn-ui-react 0.5.3 → 0.6.1

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/README.md CHANGED
@@ -18,6 +18,16 @@ pnpm add shadcn-ui-react
18
18
 
19
19
  ---
20
20
 
21
+ ### Tailwind IntelliSense (VS Code)
22
+
23
+ To enable Tailwind CSS IntelliSense to detect classes within `cn(...)` and other utilities:
24
+
25
+ ```bash
26
+ npx shadcn-ui-react init-vscode
27
+ ```
28
+
29
+ ---
30
+
21
31
  ## 🚀 Getting Started
22
32
 
23
33
  ### 1. Import Global Styles
@@ -361,65 +371,113 @@ export default function UserAuthForm() {
361
371
  ### 📊 DataTable
362
372
 
363
373
  ```tsx
364
- import React, { useState } from "react";
374
+ import React, { useMemo, useState } from "react";
375
+ import type { ColumnDef } from "@tanstack/react-table";
365
376
  import { DataTable } from "shadcn-ui-react";
366
- import { ColumnDef } from "@tanstack/react-table";
367
377
 
368
378
  type User = {
369
379
  id: number;
370
380
  name: string;
371
381
  email: string;
382
+ role: "Admin" | "Editor" | "Viewer";
372
383
  };
373
384
 
374
385
  const columns: ColumnDef<User, any>[] = [
375
386
  { accessorKey: "id", header: "ID" },
376
- { accessorKey: "name", header: "Name" },
387
+ {
388
+ accessorKey: "name",
389
+ header: "Name",
390
+ cell: ({ row }) => (
391
+ <div className="flex items-center gap-2">
392
+ <div className="h-2 w-2 rounded-full bg-primary" />
393
+ <span className="font-medium">{row.original.name}</span>
394
+ </div>
395
+ ),
396
+ },
377
397
  { accessorKey: "email", header: "Email" },
398
+ {
399
+ accessorKey: "role",
400
+ header: "Role",
401
+ cell: ({ row }) => (
402
+ <span className="inline-flex items-center rounded-full border px-2 py-0.5 text-xs">
403
+ {row.original.role}
404
+ </span>
405
+ ),
406
+ },
378
407
  ];
379
408
 
380
409
  const data: User[] = [
381
- { id: 1, name: "John Doe", email: "john@example.com" },
382
- { id: 2, name: "Jane Smith", email: "jane@example.com" },
383
- { id: 3, name: "Sam Johnson", email: "sam@example.com" },
384
- { id: 4, name: "Alice Brown", email: "alice@example.com" },
385
- { id: 5, name: "Bob White", email: "bob@example.com" },
386
- { id: 6, name: "Charlie Black", email: "charlie@example.com" },
387
- { id: 7, name: "Diana Green", email: "diana@example.com" },
388
- { id: 8, name: "Eve Blue", email: "eve@example.com" },
389
- { id: 9, name: "Frank Yellow", email: "frank@example.com" },
390
- { id: 10, name: "Grace Red", email: "grace@example.com" },
410
+ { id: 1, name: "John Doe", email: "john@example.com", role: "Admin" },
411
+ { id: 2, name: "Jane Smith", email: "jane@example.com", role: "Editor" },
412
+ { id: 3, name: "Sam Johnson", email: "sam@example.com", role: "Viewer" },
413
+ { id: 4, name: "Alice Brown", email: "alice@example.com", role: "Editor" },
414
+ { id: 5, name: "Bob White", email: "bob@example.com", role: "Viewer" },
415
+ { id: 6, name: "Charlie Black", email: "charlie@example.com", role: "Admin" },
416
+ { id: 7, name: "Diana Green", email: "diana@example.com", role: "Viewer" },
417
+ { id: 8, name: "Eve Blue", email: "eve@example.com", role: "Editor" },
418
+ { id: 9, name: "Frank Yellow", email: "frank@example.com", role: "Viewer" },
419
+ { id: 10, name: "Grace Red", email: "grace@example.com", role: "Admin" },
391
420
  ];
392
421
 
393
422
  const Example = () => {
394
423
  const [page, setPage] = useState(1);
395
424
  const [perPage, setPerPage] = useState(5);
396
425
 
397
- const paginatedData = data.slice((page - 1) * perPage, page * perPage);
426
+ const pageCount = useMemo(() => Math.ceil(data.length / perPage), [perPage]);
398
427
 
399
- const handlePageChange = (newPage: number) => setPage(newPage);
400
-
401
- const handlePageSizeChange = (newPageSize: number) => {
402
- setPerPage(newPageSize);
403
- setPage(1);
404
- };
428
+ const paginatedData = useMemo(() => {
429
+ const start = (page - 1) * perPage;
430
+ const end = page * perPage;
431
+ return data.slice(start, end);
432
+ }, [page, perPage]);
405
433
 
406
434
  return (
407
- <div>
408
- <h1 className="text-xl font-bold mb-4">Data Table with Pagination</h1>
435
+ <div className="space-y-4">
436
+ <div className="space-y-1">
437
+ <h1 className="text-xl font-bold">DataTable v2</h1>
438
+ <p className="text-sm text-muted-foreground">
439
+ Manual pagination + templates + sticky header + accent
440
+ </p>
441
+ </div>
409
442
 
410
443
  <DataTable
411
444
  columns={columns}
412
445
  data={paginatedData}
413
- pageCount={Math.ceil(data.length / perPage)}
446
+ pageCount={pageCount}
414
447
  page={page}
415
448
  perPage={perPage}
416
- onPageChange={handlePageChange}
417
- onPageSizeChange={handlePageSizeChange}
449
+ onPageChange={setPage}
450
+ onPageSizeChange={(size) => {
451
+ setPerPage(size);
452
+ setPage(1);
453
+ }}
454
+ totalRows={data.length}
455
+ isRowsSelected={false}
418
456
  rowPerPageLabel="Rows per page"
419
457
  pageLabel="Page"
420
458
  ofLabel="of"
421
459
  rowsSelectedLabel="rows selected"
422
- emptyData={<div>No data available</div>}
460
+ emptyData={<div className="py-10 text-center">No data available</div>}
461
+
462
+ // ✨ NEW (v0.6.6)
463
+ template="neo" // neo | glass | compact | minimal | clean | elevated | grid | cards
464
+ accent="primary" // primary | emerald | indigo | rose | amber | zinc
465
+ stickyHeader={true}
466
+ headerScroll={false}
467
+ animate={true}
468
+ heightClassName="h-[420px]" // Important: Define the height for the ScrollArea to work.
469
+
470
+ onClick={(row) => {
471
+ // demo: click in row
472
+ console.log("Row clicked:", row);
473
+ }}
474
+
475
+ // optional
476
+ classNames={{
477
+ // root: "border-primary/20",
478
+ // th: "text-[10px]",
479
+ // td: "py-2",
480
+ }}
423
481
  />
424
482
  </div>
425
483
  );
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const cmd = process.argv[2];
10
+
11
+ const uniq = (arr) => {
12
+ const seen = new Set();
13
+ const out = [];
14
+ for (const item of arr) {
15
+ const key = JSON.stringify(item);
16
+ if (seen.has(key)) continue;
17
+ seen.add(key);
18
+ out.push(item);
19
+ }
20
+ return out;
21
+ };
22
+
23
+ function ensureDir(dir) {
24
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
25
+ }
26
+
27
+ function readJson(p) {
28
+ if (!fs.existsSync(p)) return null;
29
+ try {
30
+ return JSON.parse(fs.readFileSync(p, "utf8"));
31
+ } catch (e) {
32
+ console.error(`❌ No pude leer JSON: ${p}`);
33
+ console.error(e?.message ?? e);
34
+ process.exit(1);
35
+ }
36
+ }
37
+
38
+ function writeJson(p, obj) {
39
+ fs.writeFileSync(p, JSON.stringify(obj, null, 2) + "\n", "utf8");
40
+ }
41
+
42
+ function initVscode() {
43
+ const tplPath = path.join(__dirname, "..", "templates", "vscode-settings.json");
44
+ const tpl = readJson(tplPath) ?? {};
45
+
46
+ const vscodeDir = path.join(process.cwd(), ".vscode");
47
+ const settingsPath = path.join(vscodeDir, "settings.json");
48
+
49
+ ensureDir(vscodeDir);
50
+
51
+ const current = readJson(settingsPath) ?? {};
52
+ const next = { ...current };
53
+
54
+ // classRegex (merge + dedupe)
55
+ const curRegex = current["tailwindCSS.experimental.classRegex"] ?? [];
56
+ const tplRegex = tpl["tailwindCSS.experimental.classRegex"] ?? [];
57
+ next["tailwindCSS.experimental.classRegex"] = uniq([
58
+ ...(Array.isArray(curRegex) ? curRegex : []),
59
+ ...(Array.isArray(tplRegex) ? tplRegex : [])
60
+ ]);
61
+
62
+ // includeLanguages (merge)
63
+ const curLang = current["tailwindCSS.includeLanguages"] ?? {};
64
+ const tplLang = tpl["tailwindCSS.includeLanguages"] ?? {};
65
+ next["tailwindCSS.includeLanguages"] = { ...(curLang || {}), ...(tplLang || {}) };
66
+
67
+ writeJson(settingsPath, next);
68
+ console.log("✅ Listo: actualizado .vscode/settings.json (Tailwind IntelliSense).");
69
+ }
70
+
71
+ function initExtensions() {
72
+ const vscodeDir = path.join(process.cwd(), ".vscode");
73
+ const extPath = path.join(vscodeDir, "extensions.json");
74
+ ensureDir(vscodeDir);
75
+
76
+ const current = readJson(extPath) ?? {};
77
+ const recs = Array.isArray(current.recommendations) ? current.recommendations : [];
78
+ const add = "bradlc.vscode-tailwindcss";
79
+
80
+ const next = {
81
+ ...current,
82
+ recommendations: Array.from(new Set([...recs, add]))
83
+ };
84
+
85
+ writeJson(extPath, next);
86
+ console.log("✅ Listo: actualizado .vscode/extensions.json (recomendación Tailwind CSS).");
87
+ }
88
+
89
+ switch (cmd) {
90
+ case "init-vscode":
91
+ initVscode();
92
+ initExtensions();
93
+ break;
94
+ default:
95
+ console.log(`Uso:
96
+ npx shadcn-ui-react init-vscode
97
+ `);
98
+ process.exit(cmd ? 1 : 0);
99
+ }