@phsa.tec/design-system-react 0.1.0

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 (201) hide show
  1. package/.eslintrc.json +7 -0
  2. package/.storybook/main.ts +16 -0
  3. package/.storybook/preview.ts +15 -0
  4. package/README.md +36 -0
  5. package/components.json +21 -0
  6. package/jest.config.ts +25 -0
  7. package/next.config.ts +7 -0
  8. package/package.json +88 -0
  9. package/postcss.config.mjs +8 -0
  10. package/public/file.svg +1 -0
  11. package/public/globe.svg +1 -0
  12. package/public/next.svg +1 -0
  13. package/public/vercel.svg +1 -0
  14. package/public/window.svg +1 -0
  15. package/src/app/columns.tsx +178 -0
  16. package/src/app/favicon.ico +0 -0
  17. package/src/app/fonts/GeistMonoVF.woff +0 -0
  18. package/src/app/fonts/GeistVF.woff +0 -0
  19. package/src/app/globals.css +94 -0
  20. package/src/app/layout.tsx +35 -0
  21. package/src/app/page.tsx +7 -0
  22. package/src/components/actions/AlertDialog/AlertDialog.tsx +45 -0
  23. package/src/components/actions/AlertDialog/alert-dialog.stories.tsx +21 -0
  24. package/src/components/actions/AlertDialog/index.ts +1 -0
  25. package/src/components/actions/Button/Button.stories.ts +38 -0
  26. package/src/components/actions/Button/Button.tsx +23 -0
  27. package/src/components/actions/Button/index.ts +1 -0
  28. package/src/components/actions/Collapsible/index.ts +1 -0
  29. package/src/components/actions/Dialog/Dialog.stories.tsx +70 -0
  30. package/src/components/actions/Dialog/Dialog.tsx +87 -0
  31. package/src/components/actions/Dialog/components/DialogWithActions/index.tsx +40 -0
  32. package/src/components/actions/Dialog/index.ts +1 -0
  33. package/src/components/actions/Steps/Steps.stories.tsx +25 -0
  34. package/src/components/actions/Steps/Steps.tsx +51 -0
  35. package/src/components/actions/Steps/index.ts +1 -0
  36. package/src/components/actions/index.ts +5 -0
  37. package/src/components/dataDisplay/Avatar/Avatar.stories.tsx +22 -0
  38. package/src/components/dataDisplay/Avatar/Avatar.tsx +21 -0
  39. package/src/components/dataDisplay/Avatar/index.ts +2 -0
  40. package/src/components/dataDisplay/Badge/Badge.stories.tsx +36 -0
  41. package/src/components/dataDisplay/Badge/index.ts +1 -0
  42. package/src/components/dataDisplay/Card/Card.stories.tsx +24 -0
  43. package/src/components/dataDisplay/Card/Card.tsx +34 -0
  44. package/src/components/dataDisplay/Card/index.ts +1 -0
  45. package/src/components/dataDisplay/DataPairList/DataPairList.tsx +56 -0
  46. package/src/components/dataDisplay/DataPairList/data-pair-list.stories.tsx +87 -0
  47. package/src/components/dataDisplay/DataPairList/index.ts +2 -0
  48. package/src/components/dataDisplay/DataPairList/types.ts +10 -0
  49. package/src/components/dataDisplay/DropDownMenu/index.ts +1 -0
  50. package/src/components/dataDisplay/ErrorMessage/ErrorMessage.tsx +6 -0
  51. package/src/components/dataDisplay/ErrorMessage/index.ts +1 -0
  52. package/src/components/dataDisplay/Icon/Icon.stories.tsx +21 -0
  53. package/src/components/dataDisplay/Icon/Icon.tsx +47 -0
  54. package/src/components/dataDisplay/Icon/index.ts +1 -0
  55. package/src/components/dataDisplay/Icon/types.ts +6 -0
  56. package/src/components/dataDisplay/Label/Label.stories.tsx +21 -0
  57. package/src/components/dataDisplay/Label/Label.tsx +10 -0
  58. package/src/components/dataDisplay/Label/index.ts +1 -0
  59. package/src/components/dataDisplay/Table/Table.tsx +173 -0
  60. package/src/components/dataDisplay/Table/columns.tsx +223 -0
  61. package/src/components/dataDisplay/Table/components/DynamicTable/data-table-column-header.tsx +72 -0
  62. package/src/components/dataDisplay/Table/components/DynamicTable/data-table-pagination.tsx +91 -0
  63. package/src/components/dataDisplay/Table/components/DynamicTable/data-table-toolbar.tsx +17 -0
  64. package/src/components/dataDisplay/Table/components/DynamicTable/data-table-view-options.tsx +58 -0
  65. package/src/components/dataDisplay/Table/components/DynamicTable/data-table.stories.tsx +118 -0
  66. package/src/components/dataDisplay/Table/components/DynamicTable/index.tsx +136 -0
  67. package/src/components/dataDisplay/Table/components/DynamicTable/types.ts +43 -0
  68. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-column-header.tsx +71 -0
  69. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-faceted-filter.tsx +147 -0
  70. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-pagination.tsx +97 -0
  71. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-row-actions.tsx +78 -0
  72. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-toolbar.tsx +60 -0
  73. package/src/components/dataDisplay/Table/custom/CustomTable/data-table-view-options.tsx +59 -0
  74. package/src/components/dataDisplay/Table/custom/CustomTable/data-table.tsx +145 -0
  75. package/src/components/dataDisplay/Table/custom/CustomTable/data.ts +71 -0
  76. package/src/components/dataDisplay/Table/custom/CustomTable/index.tsx +34 -0
  77. package/src/components/dataDisplay/Table/custom/CustomTable/schema.ts +11 -0
  78. package/src/components/dataDisplay/Table/index.ts +2 -0
  79. package/src/components/dataDisplay/Table/table.stories.tsx +147 -0
  80. package/src/components/dataDisplay/Table/types.ts +15 -0
  81. package/src/components/dataDisplay/Tabs/Tabs.stories.tsx +34 -0
  82. package/src/components/dataDisplay/Tabs/Tabs.tsx +53 -0
  83. package/src/components/dataDisplay/Tabs/index.ts +1 -0
  84. package/src/components/dataDisplay/Text/Text.stories.tsx +66 -0
  85. package/src/components/dataDisplay/Text/Text.tsx +56 -0
  86. package/src/components/dataDisplay/Text/index.ts +1 -0
  87. package/src/components/dataDisplay/index.ts +8 -0
  88. package/src/components/dataInput/Input/components/Input/Input.stories.tsx +99 -0
  89. package/src/components/dataInput/Input/components/Input/InputBase.tsx +50 -0
  90. package/src/components/dataInput/Input/components/Input/__tests__/Input.test.tsx +100 -0
  91. package/src/components/dataInput/Input/components/Input/index.tsx +257 -0
  92. package/src/components/dataInput/Input/components/InputBase/__tests__/InputBase.test.tsx +120 -0
  93. package/src/components/dataInput/Input/components/InputBase/index.tsx +89 -0
  94. package/src/components/dataInput/Input/components/MaskInput/__tests__/mask-input.test.tsx +67 -0
  95. package/src/components/dataInput/Input/components/MaskInput/index.ts +1 -0
  96. package/src/components/dataInput/Input/components/MaskInput/mask-input.stories.tsx +59 -0
  97. package/src/components/dataInput/Input/components/MaskInput/mask-input.tsx +43 -0
  98. package/src/components/dataInput/Input/components/MultipleInput/MultipleInput.tsx +36 -0
  99. package/src/components/dataInput/Input/components/MultipleInput/MultipleInputBase.tsx +100 -0
  100. package/src/components/dataInput/Input/components/MultipleInput/MultipleMaskInput.tsx +35 -0
  101. package/src/components/dataInput/Input/components/MultipleInput/MultipleNumberInput.tsx +35 -0
  102. package/src/components/dataInput/Input/components/MultipleInput/index.ts +2 -0
  103. package/src/components/dataInput/Input/components/MultipleInput/multiple-input.stories.tsx +71 -0
  104. package/src/components/dataInput/Input/components/NumberInput/__tests__/number-input.test.tsx +95 -0
  105. package/src/components/dataInput/Input/components/NumberInput/index.ts +1 -0
  106. package/src/components/dataInput/Input/components/NumberInput/number-input.stories.tsx +76 -0
  107. package/src/components/dataInput/Input/components/NumberInput/number-input.tsx +68 -0
  108. package/src/components/dataInput/Input/index.ts +4 -0
  109. package/src/components/dataInput/Select/MultiSelect/MultiSelect.stories.tsx +119 -0
  110. package/src/components/dataInput/Select/MultiSelect/MultiSelectBase.tsx +135 -0
  111. package/src/components/dataInput/Select/MultiSelect/index.tsx +75 -0
  112. package/src/components/dataInput/Select/Select.stories.tsx +61 -0
  113. package/src/components/dataInput/Select/Select.tsx +73 -0
  114. package/src/components/dataInput/Select/SelectBase.tsx +58 -0
  115. package/src/components/dataInput/Select/index.ts +2 -0
  116. package/src/components/dataInput/Switch/Switch.stories.tsx +75 -0
  117. package/src/components/dataInput/Switch/Switch.tsx +52 -0
  118. package/src/components/dataInput/Switch/index.ts +1 -0
  119. package/src/components/dataInput/checkbox/Checkbox.tsx +57 -0
  120. package/src/components/dataInput/checkbox/Checkbox_old.tsx +58 -0
  121. package/src/components/dataInput/checkbox/Checkout.stories.tsx +62 -0
  122. package/src/components/dataInput/checkbox/index.ts +1 -0
  123. package/src/components/dataInput/form/Form.tsx +47 -0
  124. package/src/components/dataInput/form/index.ts +3 -0
  125. package/src/components/dataInput/index.ts +5 -0
  126. package/src/components/feedback/Spinner/index.ts +1 -0
  127. package/src/components/feedback/Toast/Toast.stories.tsx +45 -0
  128. package/src/components/feedback/Toast/index.ts +2 -0
  129. package/src/components/feedback/index.ts +2 -0
  130. package/src/components/index.ts +6 -0
  131. package/src/components/layout/Crud/components/Table/index.tsx +183 -0
  132. package/src/components/layout/Crud/components/Table/types.ts +15 -0
  133. package/src/components/layout/Crud/crud.stories.tsx +317 -0
  134. package/src/components/layout/Crud/hook/useCrudLayout/index.tsx +94 -0
  135. package/src/components/layout/Crud/hook/useRequest/index.tsx +156 -0
  136. package/src/components/layout/Crud/index.tsx +295 -0
  137. package/src/components/layout/Crud/store/CrudLayoutStore.ts +75 -0
  138. package/src/components/layout/Crud/types.ts +14 -0
  139. package/src/components/layout/Drawer/CustomDrawer/index.tsx +33 -0
  140. package/src/components/layout/Drawer/Drawer.stories.tsx +80 -0
  141. package/src/components/layout/Drawer/index.ts +2 -0
  142. package/src/components/layout/PageLayout/PageLayout.stories.tsx +42 -0
  143. package/src/components/layout/PageLayout/index.tsx +28 -0
  144. package/src/components/layout/Separator/index.ts +1 -0
  145. package/src/components/layout/Sheet/Sheet.stories.tsx +28 -0
  146. package/src/components/layout/Sheet/Sheet.tsx +22 -0
  147. package/src/components/layout/Sheet/index.ts +1 -0
  148. package/src/components/layout/Sidebar/Sidebar.stories.tsx +116 -0
  149. package/src/components/layout/Sidebar/Sidebar.tsx +50 -0
  150. package/src/components/layout/Sidebar/components/app-sidebar.tsx +203 -0
  151. package/src/components/layout/Sidebar/components/footer-sidebar.tsx +17 -0
  152. package/src/components/layout/Sidebar/components/header-sidebar.tsx +90 -0
  153. package/src/components/layout/Sidebar/components/menus.tsx +55 -0
  154. package/src/components/layout/Sidebar/components/nav-projects.tsx +88 -0
  155. package/src/components/layout/Sidebar/components/nav-user.tsx +114 -0
  156. package/src/components/layout/Sidebar/components/team-switcher.tsx +85 -0
  157. package/src/components/layout/Sidebar/index.ts +2 -0
  158. package/src/components/layout/Sidebar/provider/index.tsx +51 -0
  159. package/src/components/layout/Tabs/Tabs.tsx +51 -0
  160. package/src/components/layout/Tabs/index.ts +1 -0
  161. package/src/components/layout/Tabs/tabs.stories.tsx +57 -0
  162. package/src/components/layout/index.ts +6 -0
  163. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +66 -0
  164. package/src/components/navigation/Breadcrumbs/index.ts +2 -0
  165. package/src/components/navigation/index.ts +1 -0
  166. package/src/components/ui/alert-dialog.tsx +141 -0
  167. package/src/components/ui/alert.tsx +59 -0
  168. package/src/components/ui/avatar.tsx +50 -0
  169. package/src/components/ui/badge.tsx +40 -0
  170. package/src/components/ui/breadcrumb.tsx +115 -0
  171. package/src/components/ui/button.tsx +57 -0
  172. package/src/components/ui/card.tsx +83 -0
  173. package/src/components/ui/checkbox.tsx +34 -0
  174. package/src/components/ui/collapsible.tsx +11 -0
  175. package/src/components/ui/command.tsx +153 -0
  176. package/src/components/ui/dialog.tsx +124 -0
  177. package/src/components/ui/drawer.tsx +117 -0
  178. package/src/components/ui/dropdown-menu.tsx +201 -0
  179. package/src/components/ui/form.tsx +179 -0
  180. package/src/components/ui/input.tsx +24 -0
  181. package/src/components/ui/label.tsx +30 -0
  182. package/src/components/ui/popover.tsx +33 -0
  183. package/src/components/ui/select.tsx +161 -0
  184. package/src/components/ui/separator.tsx +31 -0
  185. package/src/components/ui/sheet.tsx +140 -0
  186. package/src/components/ui/sidebar.tsx +763 -0
  187. package/src/components/ui/skeleton.tsx +15 -0
  188. package/src/components/ui/sonner.tsx +31 -0
  189. package/src/components/ui/spinner.tsx +54 -0
  190. package/src/components/ui/switch.tsx +33 -0
  191. package/src/components/ui/table.tsx +120 -0
  192. package/src/components/ui/tabs.tsx +55 -0
  193. package/src/components/ui/toast.tsx +130 -0
  194. package/src/components/ui/toaster.tsx +35 -0
  195. package/src/components/ui/tooltip.tsx +32 -0
  196. package/src/hooks/use-mobile.tsx +19 -0
  197. package/src/hooks/use-toast.ts +191 -0
  198. package/src/index.ts +1 -0
  199. package/src/lib/utils.ts +6 -0
  200. package/tailwind.config.ts +83 -0
  201. package/tsconfig.json +27 -0
@@ -0,0 +1,21 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs";
2
+
3
+ import { Icon } from "./index";
4
+
5
+ const meta = {
6
+ title: "DataDisplay/Icon",
7
+ component: Icon,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ tags: ["autodocs"],
12
+ } satisfies Meta<typeof Icon>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ name: "MdHome",
20
+ },
21
+ };
@@ -0,0 +1,47 @@
1
+ import React, { useCallback, useMemo } from "react";
2
+ import { IconContext } from "react-icons";
3
+ import { IconProps } from "./types";
4
+
5
+ export const Icon: React.FC<IconProps> = ({ name, size = 24, ...rest }) => {
6
+ const nameIcon = useMemo(() => name, [name]);
7
+
8
+ const iconsModulePath = useMemo(
9
+ () => ({
10
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
11
+ md: require("react-icons/md"),
12
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
13
+ fa: require("react-icons/fa"),
14
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
15
+ bs: require("react-icons/bs"),
16
+ }),
17
+ []
18
+ );
19
+
20
+ const typeIcon = useMemo(() => {
21
+ const matches = [...nameIcon.matchAll(/[A-Z]/g)];
22
+ return String(
23
+ nameIcon.slice(0, matches[1]?.index) || ""
24
+ ).toLocaleLowerCase();
25
+ }, [nameIcon]);
26
+
27
+ const Icon = useCallback(
28
+ (props: typeof rest) => {
29
+ try {
30
+ if (!typeIcon || !nameIcon) return <></>;
31
+
32
+ return iconsModulePath[typeIcon as keyof typeof iconsModulePath][
33
+ nameIcon
34
+ ]?.(props);
35
+ } catch {
36
+ return <></>;
37
+ }
38
+ },
39
+ [iconsModulePath, nameIcon, typeIcon]
40
+ );
41
+
42
+ return (
43
+ <IconContext.Provider value={{ size: String(size) }}>
44
+ <Icon {...rest} />
45
+ </IconContext.Provider>
46
+ );
47
+ };
@@ -0,0 +1 @@
1
+ export * from "./Icon";
@@ -0,0 +1,6 @@
1
+ export type IconProps = {
2
+ name: string;
3
+ size?: number;
4
+ className?: string;
5
+ color?: string;
6
+ };
@@ -0,0 +1,21 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs";
2
+
3
+ import { Label } from "./index";
4
+
5
+ const meta = {
6
+ title: "DataDisplay/Label",
7
+ component: Label,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ tags: ["autodocs"],
12
+ } satisfies Meta<typeof Label>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ children: "Label",
20
+ },
21
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ Label as LabelComponent,
3
+ LabelProps as LabelComponentProps,
4
+ } from "../../ui/label";
5
+
6
+ export type LabelProps = LabelComponentProps;
7
+
8
+ export const Label = (props: LabelProps) => {
9
+ return <LabelComponent {...props} />;
10
+ };
@@ -0,0 +1 @@
1
+ export * from "./Label";
@@ -0,0 +1,173 @@
1
+ "use client";
2
+
3
+ import {
4
+ ChevronDown,
5
+ ChevronUp,
6
+ ChevronLeft,
7
+ ChevronRight,
8
+ } from "lucide-react";
9
+ import {
10
+ Table as ShadcnTable,
11
+ TableBody,
12
+ TableCell,
13
+ TableHead,
14
+ TableHeader,
15
+ TableRow,
16
+ } from "@/components/ui/table";
17
+ import { Button } from "@/components/ui/button";
18
+ import {
19
+ ColumnDef,
20
+ SortingState,
21
+ flexRender,
22
+ getCoreRowModel,
23
+ getSortedRowModel,
24
+ getPaginationRowModel,
25
+ useReactTable,
26
+ PaginationState,
27
+ } from "@tanstack/react-table";
28
+
29
+ export interface TableProps<TData> {
30
+ data: TData[];
31
+ columns: ColumnDef<TData, unknown>[];
32
+ pageSize?: number;
33
+ onSortingChange?: (sorting: SortingState) => void;
34
+ sorting?: SortingState;
35
+ onPaginationChange?: (pagination: PaginationState) => void;
36
+ pagination?: PaginationState;
37
+ emptyMessage?: string;
38
+ }
39
+
40
+ export function Table<TData>({
41
+ data,
42
+ columns,
43
+ onSortingChange = () => {},
44
+ sorting = [],
45
+ pagination = { pageIndex: 0, pageSize: 0 },
46
+ onPaginationChange = () => {},
47
+ emptyMessage = "No results.",
48
+ }: TableProps<TData>) {
49
+ const table = useReactTable({
50
+ data,
51
+ columns,
52
+ state: {
53
+ sorting,
54
+ },
55
+ onSortingChange: (sorting) => {
56
+ onSortingChange(sorting as SortingState);
57
+ },
58
+ getCoreRowModel: getCoreRowModel(),
59
+ getSortedRowModel: getSortedRowModel(),
60
+ getPaginationRowModel: getPaginationRowModel(),
61
+ onPaginationChange: (pagination) => {
62
+ onPaginationChange(pagination as PaginationState);
63
+ },
64
+ initialState: {
65
+ pagination,
66
+ },
67
+ });
68
+
69
+ const getSortingIcons = (column: {
70
+ getIsSorted: () => string | false;
71
+ getCanSort: () => boolean;
72
+ }) => {
73
+ const sortDirection = column.getIsSorted();
74
+
75
+ if (!column.getCanSort()) return null;
76
+
77
+ if (sortDirection === "asc") {
78
+ return <ChevronUp className="ml-2 h-4 w-4 inline" />;
79
+ } else if (sortDirection === "desc") {
80
+ return <ChevronDown className="ml-2 h-4 w-4 inline" />;
81
+ }
82
+
83
+ return (
84
+ <div className="ml-2 inline-flex flex-col">
85
+ <ChevronUp className="h-3 w-3" />
86
+ <ChevronDown className="h-3 w-3 -mt-1" />
87
+ </div>
88
+ );
89
+ };
90
+
91
+ return (
92
+ <div className="rounded-md border">
93
+ <ShadcnTable>
94
+ <TableHeader>
95
+ {table.getHeaderGroups().map((headerGroup) => (
96
+ <TableRow key={headerGroup.id}>
97
+ {headerGroup.headers.map((header) => (
98
+ <TableHead key={header.id}>
99
+ {header.isPlaceholder ? null : (
100
+ <div
101
+ className={
102
+ header.column.getCanSort()
103
+ ? "cursor-pointer select-none flex items-center"
104
+ : ""
105
+ }
106
+ onClick={header.column.getToggleSortingHandler()}
107
+ >
108
+ {flexRender(
109
+ header.column.columnDef.header,
110
+ header.getContext()
111
+ )}
112
+ {getSortingIcons(header.column)}
113
+ </div>
114
+ )}
115
+ </TableHead>
116
+ ))}
117
+ </TableRow>
118
+ ))}
119
+ </TableHeader>
120
+ <TableBody>
121
+ {table.getRowModel().rows.length ? (
122
+ table.getRowModel().rows.map((row) => (
123
+ <TableRow key={row.id}>
124
+ {row.getVisibleCells().map((cell) => (
125
+ <TableCell key={cell.id}>
126
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
127
+ </TableCell>
128
+ ))}
129
+ </TableRow>
130
+ ))
131
+ ) : (
132
+ <TableRow>
133
+ <TableCell colSpan={columns.length} className="h-24 text-center">
134
+ {emptyMessage}
135
+ </TableCell>
136
+ </TableRow>
137
+ )}
138
+ </TableBody>
139
+ </ShadcnTable>
140
+
141
+ <div className="flex items-center justify-end space-x-2 py-4 px-4 border-t">
142
+ <div className="flex-1 text-sm text-muted-foreground">
143
+ {table.getFilteredRowModel().rows.length} row(s) total
144
+ </div>
145
+ <div className="space-x-2">
146
+ <Button
147
+ variant="outline"
148
+ size="sm"
149
+ onClick={() => table.previousPage()}
150
+ disabled={!table.getCanPreviousPage()}
151
+ >
152
+ <ChevronLeft className="h-4 w-4" />
153
+ </Button>
154
+ <Button
155
+ variant="outline"
156
+ size="sm"
157
+ onClick={() => table.nextPage()}
158
+ disabled={!table.getCanNextPage()}
159
+ >
160
+ <ChevronRight className="h-4 w-4" />
161
+ </Button>
162
+ </div>
163
+ <div className="flex items-center gap-1">
164
+ <p className="text-sm font-medium">Page</p>
165
+ <span className="text-sm font-medium">
166
+ {table.getState().pagination.pageIndex + 1} of{" "}
167
+ {table.getPageCount() || 0}
168
+ </span>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ );
173
+ }
@@ -0,0 +1,223 @@
1
+ "use client";
2
+
3
+ import { ColumnDef } from "@tanstack/react-table";
4
+ import { Checkbox } from "../../../components/ui/checkbox";
5
+ import { z } from "zod";
6
+ import {
7
+ ArrowDownIcon,
8
+ ArrowRightIcon,
9
+ ArrowUpIcon,
10
+ CheckCircledIcon,
11
+ CircleIcon,
12
+ CrossCircledIcon,
13
+ QuestionMarkCircledIcon,
14
+ StopwatchIcon,
15
+ } from "@radix-ui/react-icons";
16
+ import { DataTableColumnHeader } from "./custom/CustomTable/data-table-column-header";
17
+ import { Badge } from "../../../components/ui/badge";
18
+ import { DataTableRowActions } from "./custom/CustomTable/data-table-row-actions";
19
+
20
+ export const labels = [
21
+ {
22
+ value: "bug",
23
+ label: "Bug",
24
+ },
25
+ {
26
+ value: "feature",
27
+ label: "Feature",
28
+ },
29
+ {
30
+ value: "documentation",
31
+ label: "Documentation",
32
+ },
33
+ ];
34
+
35
+ export const statuses = [
36
+ {
37
+ value: "backlog",
38
+ label: "Backlog",
39
+ icon: QuestionMarkCircledIcon,
40
+ },
41
+ {
42
+ value: "todo",
43
+ label: "Todo",
44
+ icon: CircleIcon,
45
+ },
46
+ {
47
+ value: "in progress",
48
+ label: "In Progress",
49
+ icon: StopwatchIcon,
50
+ },
51
+ {
52
+ value: "done",
53
+ label: "Done",
54
+ icon: CheckCircledIcon,
55
+ },
56
+ {
57
+ value: "canceled",
58
+ label: "Canceled",
59
+ icon: CrossCircledIcon,
60
+ },
61
+ ];
62
+
63
+ export const priorities = [
64
+ {
65
+ label: "Low",
66
+ value: "low",
67
+ icon: ArrowDownIcon,
68
+ },
69
+ {
70
+ label: "Medium",
71
+ value: "medium",
72
+ icon: ArrowRightIcon,
73
+ },
74
+ {
75
+ label: "High",
76
+ value: "high",
77
+ icon: ArrowUpIcon,
78
+ },
79
+ ];
80
+
81
+ export const taskSchema = z.object({
82
+ id: z.string(),
83
+ title: z.string(),
84
+ status: z.string(),
85
+ label: z.string(),
86
+ priority: z.string(),
87
+ });
88
+
89
+ export type Task = z.infer<typeof taskSchema>;
90
+
91
+ export const columns: ColumnDef<Task>[] = [
92
+ {
93
+ id: "select",
94
+ header: ({ table }) => (
95
+ <Checkbox
96
+ checked={
97
+ table.getIsAllPageRowsSelected() ||
98
+ (table.getIsSomePageRowsSelected() && "indeterminate")
99
+ }
100
+ onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
101
+ aria-label="Select all"
102
+ className="translate-y-[2px]"
103
+ />
104
+ ),
105
+ cell: ({ row }) => (
106
+ <Checkbox
107
+ checked={row.getIsSelected()}
108
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
109
+ aria-label="Select row"
110
+ className="translate-y-[2px]"
111
+ />
112
+ ),
113
+ enableSorting: false,
114
+ enableHiding: false,
115
+ },
116
+ {
117
+ accessorKey: "id",
118
+ header: ({ column }) => (
119
+ <DataTableColumnHeader column={column} title="Task" />
120
+ ),
121
+ cell: ({ row }) => <div className="w-[80px]">{row.getValue("id")}</div>,
122
+ enableSorting: false,
123
+ enableHiding: false,
124
+ },
125
+ {
126
+ accessorKey: "title",
127
+ header: ({ column }) => (
128
+ <DataTableColumnHeader column={column} title="Title" />
129
+ ),
130
+ cell: ({ row }) => {
131
+ const label = labels.find((label) => label.value === row.original.label);
132
+
133
+ return (
134
+ <div className="flex space-x-2">
135
+ {label && <Badge variant="outline">{label.label}</Badge>}
136
+ <span className="max-w-[500px] truncate font-medium">
137
+ {row.getValue("title")}
138
+ </span>
139
+ </div>
140
+ );
141
+ },
142
+ },
143
+ {
144
+ accessorKey: "status",
145
+ header: ({ column }) => (
146
+ <DataTableColumnHeader column={column} title="Status" />
147
+ ),
148
+ cell: ({ row }) => {
149
+ const status = statuses.find(
150
+ (status) => status.value === row.getValue("status")
151
+ );
152
+
153
+ if (!status) {
154
+ return null;
155
+ }
156
+
157
+ return (
158
+ <div className="flex w-[100px] items-center">
159
+ {status.icon && (
160
+ <status.icon className="mr-2 h-4 w-4 text-muted-foreground" />
161
+ )}
162
+ <span>{status.label}</span>
163
+ </div>
164
+ );
165
+ },
166
+ filterFn: (row, id, value) => {
167
+ return value.includes(row.getValue(id));
168
+ },
169
+ },
170
+ {
171
+ accessorKey: "priority",
172
+ header: ({ column }) => (
173
+ <DataTableColumnHeader column={column} title="Priority" />
174
+ ),
175
+ cell: ({ row }) => {
176
+ const priority = priorities.find(
177
+ (priority) => priority.value === row.getValue("priority")
178
+ );
179
+
180
+ if (!priority) {
181
+ return null;
182
+ }
183
+
184
+ return (
185
+ <div className="flex items-center">
186
+ {priority.icon && (
187
+ <priority.icon className="mr-2 h-4 w-4 text-muted-foreground" />
188
+ )}
189
+ <span>{priority.label}</span>
190
+ </div>
191
+ );
192
+ },
193
+ filterFn: (row, id, value) => {
194
+ return value.includes(row.getValue(id));
195
+ },
196
+ },
197
+ {
198
+ id: "actions",
199
+ cell: ({ row }) => (
200
+ <DataTableRowActions
201
+ row={row}
202
+ options={[
203
+ {
204
+ action: () => alert("Edit"),
205
+ label: "Edit",
206
+ },
207
+ {
208
+ action: () => alert("Make a copy"),
209
+ label: "Make a copy",
210
+ },
211
+ {
212
+ action: () => alert("Favorite"),
213
+ label: "Favorite",
214
+ },
215
+ {
216
+ action: () => alert("Delete"),
217
+ label: "Delete",
218
+ },
219
+ ]}
220
+ />
221
+ ),
222
+ },
223
+ ];
@@ -0,0 +1,72 @@
1
+ "use client";
2
+
3
+ import {
4
+ ArrowDownIcon,
5
+ ArrowUpIcon,
6
+ CaretSortIcon,
7
+ EyeNoneIcon,
8
+ } from "@radix-ui/react-icons";
9
+ import { Column } from "@tanstack/react-table";
10
+ import { cn } from "../../../../../lib/utils";
11
+ import { Button } from "../../../../../components/ui/button";
12
+ import {
13
+ DropdownMenu,
14
+ DropdownMenuContent,
15
+ DropdownMenuItem,
16
+ DropdownMenuSeparator,
17
+ DropdownMenuTrigger,
18
+ } from "../../../../../components/ui/dropdown-menu";
19
+
20
+ interface DataTableColumnHeaderProps<TData, TValue>
21
+ extends React.HTMLAttributes<HTMLDivElement> {
22
+ column: Column<TData, TValue>;
23
+ title: string;
24
+ }
25
+
26
+ export function DataTableColumnHeader<TData, TValue>({
27
+ column,
28
+ title,
29
+ className,
30
+ }: DataTableColumnHeaderProps<TData, TValue>) {
31
+ if (!column.getCanSort()) {
32
+ return <div className={cn(className)}>{title}</div>;
33
+ }
34
+
35
+ return (
36
+ <div className={cn("flex items-center space-x-2", className)}>
37
+ <DropdownMenu>
38
+ <DropdownMenuTrigger asChild>
39
+ <Button
40
+ variant="ghost"
41
+ size="sm"
42
+ className="-ml-3 h-8 data-[state=open]:bg-accent"
43
+ >
44
+ <span>{title}</span>
45
+ {column.getIsSorted() === "desc" ? (
46
+ <ArrowDownIcon className="ml-2 h-4 w-4" />
47
+ ) : column.getIsSorted() === "asc" ? (
48
+ <ArrowUpIcon className="ml-2 h-4 w-4" />
49
+ ) : (
50
+ <CaretSortIcon className="ml-2 h-4 w-4" />
51
+ )}
52
+ </Button>
53
+ </DropdownMenuTrigger>
54
+ <DropdownMenuContent align="start">
55
+ <DropdownMenuItem onClick={() => column.toggleSorting(false)}>
56
+ <ArrowUpIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
57
+ Crescente
58
+ </DropdownMenuItem>
59
+ <DropdownMenuItem onClick={() => column.toggleSorting(true)}>
60
+ <ArrowDownIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
61
+ Decrescente
62
+ </DropdownMenuItem>
63
+ <DropdownMenuSeparator />
64
+ <DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
65
+ <EyeNoneIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
66
+ Ocultar
67
+ </DropdownMenuItem>
68
+ </DropdownMenuContent>
69
+ </DropdownMenu>
70
+ </div>
71
+ );
72
+ }
@@ -0,0 +1,91 @@
1
+ "use client";
2
+
3
+ import {
4
+ ChevronLeftIcon,
5
+ ChevronRightIcon,
6
+ DoubleArrowLeftIcon,
7
+ DoubleArrowRightIcon,
8
+ } from "@radix-ui/react-icons";
9
+ import { Button } from "../../../../../components/ui/button";
10
+ import {
11
+ Select,
12
+ SelectContent,
13
+ SelectItem,
14
+ SelectTrigger,
15
+ SelectValue,
16
+ } from "../../../../../components/ui/select";
17
+ import { DynamicTablePaginationProps } from "./types";
18
+
19
+ export function DataTablePagination<TData>({
20
+ table,
21
+ pageSizeOptions = [10, 20, 30, 40, 50],
22
+ }: DynamicTablePaginationProps<TData>) {
23
+ return (
24
+ <div className="flex items-center justify-between px-2">
25
+ <div className="flex-1 text-sm text-muted-foreground">
26
+ {table.getFilteredSelectedRowModel().rows.length} de{" "}
27
+ {table.getFilteredRowModel().rows.length} linha(s) selecionada(s).
28
+ </div>
29
+ <div className="flex items-center space-x-6 lg:space-x-8">
30
+ <div className="flex items-center space-x-2">
31
+ <p className="text-sm font-medium">Linhas por página</p>
32
+ <Select
33
+ value={`${table.getState().pagination.pageSize}`}
34
+ onValueChange={(value) => {
35
+ table.setPageSize(Number(value));
36
+ }}
37
+ >
38
+ <SelectTrigger className="h-8 w-[70px]">
39
+ <SelectValue placeholder={table.getState().pagination.pageSize} />
40
+ </SelectTrigger>
41
+ <SelectContent side="top">
42
+ {pageSizeOptions.map((pageSize) => (
43
+ <SelectItem key={pageSize} value={`${pageSize}`}>
44
+ {pageSize}
45
+ </SelectItem>
46
+ ))}
47
+ </SelectContent>
48
+ </Select>
49
+ </div>
50
+ <div className="flex w-[100px] items-center justify-center text-sm font-medium">
51
+ Página {table.getState().pagination.pageIndex + 1} de{" "}
52
+ {table.getPageCount()}
53
+ </div>
54
+ <div className="flex items-center space-x-2">
55
+ <Button
56
+ variant="outline"
57
+ className="hidden h-8 w-8 p-0 lg:flex"
58
+ onClick={() => table.setPageIndex(0)}
59
+ disabled={!table.getCanPreviousPage()}
60
+ >
61
+ <DoubleArrowLeftIcon className="h-4 w-4" />
62
+ </Button>
63
+ <Button
64
+ variant="outline"
65
+ className="h-8 w-8 p-0"
66
+ onClick={() => table.previousPage()}
67
+ disabled={!table.getCanPreviousPage()}
68
+ >
69
+ <ChevronLeftIcon className="h-4 w-4" />
70
+ </Button>
71
+ <Button
72
+ variant="outline"
73
+ className="h-8 w-8 p-0"
74
+ onClick={() => table.nextPage()}
75
+ disabled={!table.getCanNextPage()}
76
+ >
77
+ <ChevronRightIcon className="h-4 w-4" />
78
+ </Button>
79
+ <Button
80
+ variant="outline"
81
+ className="hidden h-8 w-8 p-0 lg:flex"
82
+ onClick={() => table.setPageIndex(table.getPageCount() - 1)}
83
+ disabled={!table.getCanNextPage()}
84
+ >
85
+ <DoubleArrowRightIcon className="h-4 w-4" />
86
+ </Button>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ );
91
+ }
@@ -0,0 +1,17 @@
1
+ "use client";
2
+
3
+ import { DataTableViewOptions } from "./data-table-view-options";
4
+ import { DynamicTableToolbarProps } from "./types";
5
+
6
+ export function DataTableToolbar<TData>({
7
+ table,
8
+ filters,
9
+ showColumnVisibility,
10
+ }: DynamicTableToolbarProps<TData>) {
11
+ return (
12
+ <div className="flex items-center justify-between">
13
+ <div className="flex flex-1 items-center space-x-2">{filters}</div>
14
+ {showColumnVisibility && <DataTableViewOptions table={table} />}
15
+ </div>
16
+ );
17
+ }