@ayasofyazilim/ui 0.0.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 (236) hide show
  1. package/__mocks__/canvas.ts +8 -0
  2. package/components.json +21 -0
  3. package/eslint.config.js +4 -0
  4. package/jest-environment.js +37 -0
  5. package/jest.config.ts +47 -0
  6. package/jest.setup.ts +69 -0
  7. package/package.json +124 -0
  8. package/postcss.config.mjs +6 -0
  9. package/src/aria/index.tsx +1 -0
  10. package/src/aria/number-field.tsx +41 -0
  11. package/src/components/.gitkeep +0 -0
  12. package/src/components/accordion.tsx +66 -0
  13. package/src/components/alert-dialog.tsx +157 -0
  14. package/src/components/alert.tsx +70 -0
  15. package/src/components/aspect-ratio.tsx +11 -0
  16. package/src/components/avatar.tsx +53 -0
  17. package/src/components/badge.tsx +67 -0
  18. package/src/components/breadcrumb.tsx +109 -0
  19. package/src/components/button-group.tsx +83 -0
  20. package/src/components/button.tsx +68 -0
  21. package/src/components/calendar.tsx +219 -0
  22. package/src/components/card.tsx +92 -0
  23. package/src/components/carousel.tsx +241 -0
  24. package/src/components/chart.tsx +363 -0
  25. package/src/components/checkbox.tsx +32 -0
  26. package/src/components/collapsible.tsx +33 -0
  27. package/src/components/command.tsx +184 -0
  28. package/src/components/context-menu.tsx +252 -0
  29. package/src/components/dialog.tsx +144 -0
  30. package/src/components/drawer.tsx +135 -0
  31. package/src/components/dropdown-menu.tsx +258 -0
  32. package/src/components/empty.tsx +100 -0
  33. package/src/components/field.tsx +248 -0
  34. package/src/components/form.tsx +169 -0
  35. package/src/components/hover-card.tsx +44 -0
  36. package/src/components/input-group.tsx +170 -0
  37. package/src/components/input-otp.tsx +77 -0
  38. package/src/components/input.tsx +21 -0
  39. package/src/components/item.tsx +193 -0
  40. package/src/components/kbd.tsx +28 -0
  41. package/src/components/label.tsx +24 -0
  42. package/src/components/menubar.tsx +276 -0
  43. package/src/components/navigation-menu.tsx +168 -0
  44. package/src/components/pagination.tsx +130 -0
  45. package/src/components/popover.tsx +88 -0
  46. package/src/components/progress.tsx +31 -0
  47. package/src/components/radio-group.tsx +45 -0
  48. package/src/components/resizable.tsx +56 -0
  49. package/src/components/scroll-area.tsx +58 -0
  50. package/src/components/select.tsx +189 -0
  51. package/src/components/separator.tsx +28 -0
  52. package/src/components/sheet.tsx +140 -0
  53. package/src/components/sidebar.tsx +862 -0
  54. package/src/components/skeleton.tsx +13 -0
  55. package/src/components/slider.tsx +63 -0
  56. package/src/components/sonner.tsx +40 -0
  57. package/src/components/spinner.tsx +16 -0
  58. package/src/components/stepper.tsx +291 -0
  59. package/src/components/switch.tsx +31 -0
  60. package/src/components/table.tsx +133 -0
  61. package/src/components/tabs.tsx +66 -0
  62. package/src/components/textarea.tsx +18 -0
  63. package/src/components/toggle-group.tsx +83 -0
  64. package/src/components/toggle.tsx +47 -0
  65. package/src/components/tooltip.tsx +66 -0
  66. package/src/custom/action-button.tsx +48 -0
  67. package/src/custom/async-select.tsx +287 -0
  68. package/src/custom/awesome-not-found.tsx +116 -0
  69. package/src/custom/charts/area-chart.tsx +147 -0
  70. package/src/custom/charts/bar-chart.tsx +233 -0
  71. package/src/custom/charts/chart-card.tsx +103 -0
  72. package/src/custom/charts/index.tsx +16 -0
  73. package/src/custom/charts/pie-chart.tsx +168 -0
  74. package/src/custom/charts/radar-chart.tsx +126 -0
  75. package/src/custom/checkbox-tree.tsx +100 -0
  76. package/src/custom/combobox.tsx +296 -0
  77. package/src/custom/confirm-dialog.tsx +102 -0
  78. package/src/custom/country-selector.tsx +204 -0
  79. package/src/custom/date-picker/calendar-rac.tsx +109 -0
  80. package/src/custom/date-picker/datefield-rac.tsx +84 -0
  81. package/src/custom/date-picker/index.tsx +273 -0
  82. package/src/custom/date-picker/types/index.ts +4 -0
  83. package/src/custom/date-picker/utils/index.ts +42 -0
  84. package/src/custom/date-picker-old.tsx +50 -0
  85. package/src/custom/date-tooltip.tsx +98 -0
  86. package/src/custom/document-scanner/consts.ts +5 -0
  87. package/src/custom/document-scanner/corner-adjustment/action-buttons.tsx +33 -0
  88. package/src/custom/document-scanner/corner-adjustment/corner-handle.tsx +43 -0
  89. package/src/custom/document-scanner/corner-adjustment/hooks/use-corner-drag.ts +85 -0
  90. package/src/custom/document-scanner/corner-adjustment/index.tsx +125 -0
  91. package/src/custom/document-scanner/corner-adjustment/types.ts +53 -0
  92. package/src/custom/document-scanner/corner-adjustment/utils/clip-path.ts +22 -0
  93. package/src/custom/document-scanner/corner-adjustment/zoom-magnifier.tsx +115 -0
  94. package/src/custom/document-scanner/hooks/use-document-capture.ts +81 -0
  95. package/src/custom/document-scanner/hooks/use-document-scanner.ts +80 -0
  96. package/src/custom/document-scanner/hooks/use-perspective-crop.ts +38 -0
  97. package/src/custom/document-scanner/index.tsx +255 -0
  98. package/src/custom/document-scanner/lib.ts +407 -0
  99. package/src/custom/document-scanner/types.ts +205 -0
  100. package/src/custom/document-scanner/utils/perspective-correction.ts +139 -0
  101. package/src/custom/document-viewer/controllers.tsx +98 -0
  102. package/src/custom/document-viewer/index.tsx +43 -0
  103. package/src/custom/document-viewer/renderers/image.tsx +37 -0
  104. package/src/custom/document-viewer/renderers/index.tsx +2 -0
  105. package/src/custom/document-viewer/renderers/pdf.tsx +105 -0
  106. package/src/custom/email-input/domains.json +159 -0
  107. package/src/custom/email-input/email.tsx +229 -0
  108. package/src/custom/email-input/index.tsx +4 -0
  109. package/src/custom/email-input/types.ts +104 -0
  110. package/src/custom/file-uploader.tsx +541 -0
  111. package/src/custom/filter-component/fields/async-select.tsx +33 -0
  112. package/src/custom/filter-component/fields/date.tsx +60 -0
  113. package/src/custom/filter-component/fields/multi-select.tsx +30 -0
  114. package/src/custom/filter-component/index.tsx +217 -0
  115. package/src/custom/image-canvas.tsx +260 -0
  116. package/src/custom/json-editor.tsx +22 -0
  117. package/src/custom/master-data-grid/components/dialogs/column-settings-dialog.tsx +100 -0
  118. package/src/custom/master-data-grid/components/dialogs/index.ts +1 -0
  119. package/src/custom/master-data-grid/components/filters/client-filter.tsx +368 -0
  120. package/src/custom/master-data-grid/components/filters/filter-input.tsx +256 -0
  121. package/src/custom/master-data-grid/components/filters/index.ts +3 -0
  122. package/src/custom/master-data-grid/components/filters/inline-column-filter.tsx +233 -0
  123. package/src/custom/master-data-grid/components/filters/multi-filter-dialog.tsx +90 -0
  124. package/src/custom/master-data-grid/components/filters/server-filter.tsx +255 -0
  125. package/src/custom/master-data-grid/components/master-data-grid.tsx +472 -0
  126. package/src/custom/master-data-grid/components/pagination/index.ts +1 -0
  127. package/src/custom/master-data-grid/components/pagination/pagination.tsx +178 -0
  128. package/src/custom/master-data-grid/components/table/cell-renderer.tsx +634 -0
  129. package/src/custom/master-data-grid/components/table/header-cell.tsx +162 -0
  130. package/src/custom/master-data-grid/components/table/index.ts +4 -0
  131. package/src/custom/master-data-grid/components/table/table-body-renderer.tsx +113 -0
  132. package/src/custom/master-data-grid/components/table/virtual-body.tsx +138 -0
  133. package/src/custom/master-data-grid/components/toolbar/index.ts +1 -0
  134. package/src/custom/master-data-grid/components/toolbar/toolbar.tsx +314 -0
  135. package/src/custom/master-data-grid/hooks/index.ts +3 -0
  136. package/src/custom/master-data-grid/hooks/use-columns.tsx +332 -0
  137. package/src/custom/master-data-grid/hooks/use-editing.ts +106 -0
  138. package/src/custom/master-data-grid/hooks/use-table-state-reducer.ts +157 -0
  139. package/src/custom/master-data-grid/hooks/use-table-state.ts +31 -0
  140. package/src/custom/master-data-grid/index.ts +16 -0
  141. package/src/custom/master-data-grid/types.ts +466 -0
  142. package/src/custom/master-data-grid/utils/column-generator.tsx +306 -0
  143. package/src/custom/master-data-grid/utils/export-utils.ts +67 -0
  144. package/src/custom/master-data-grid/utils/filter-fns.ts +290 -0
  145. package/src/custom/master-data-grid/utils/index.ts +8 -0
  146. package/src/custom/master-data-grid/utils/pinning-utils.ts +88 -0
  147. package/src/custom/master-data-grid/utils/translation-utils.ts +42 -0
  148. package/src/custom/multi-select.tsx +432 -0
  149. package/src/custom/password-input.tsx +194 -0
  150. package/src/custom/phone-input.tsx +172 -0
  151. package/src/custom/schema-form/custom/index.tsx +1 -0
  152. package/src/custom/schema-form/custom/label.tsx +53 -0
  153. package/src/custom/schema-form/fields/base-input-field.tsx +82 -0
  154. package/src/custom/schema-form/fields/field.tsx +67 -0
  155. package/src/custom/schema-form/fields/index.tsx +5 -0
  156. package/src/custom/schema-form/fields/object.tsx +12 -0
  157. package/src/custom/schema-form/fields/table-array/array-field-item.tsx +90 -0
  158. package/src/custom/schema-form/fields/table-array/array-field-template.tsx +115 -0
  159. package/src/custom/schema-form/index.tsx +259 -0
  160. package/src/custom/schema-form/templates/description.tsx +20 -0
  161. package/src/custom/schema-form/templates/index.tsx +2 -0
  162. package/src/custom/schema-form/templates/submit.tsx +32 -0
  163. package/src/custom/schema-form/types.ts +64 -0
  164. package/src/custom/schema-form/utils/index.ts +4 -0
  165. package/src/custom/schema-form/utils/schema-dependency.ts +655 -0
  166. package/src/custom/schema-form/utils/schemas.ts +289 -0
  167. package/src/custom/schema-form/utils/validation.ts +23 -0
  168. package/src/custom/schema-form/widgets/boolean.tsx +77 -0
  169. package/src/custom/schema-form/widgets/combobox.tsx +274 -0
  170. package/src/custom/schema-form/widgets/date.tsx +59 -0
  171. package/src/custom/schema-form/widgets/email.tsx +34 -0
  172. package/src/custom/schema-form/widgets/index.tsx +10 -0
  173. package/src/custom/schema-form/widgets/password.tsx +40 -0
  174. package/src/custom/schema-form/widgets/phone.tsx +40 -0
  175. package/src/custom/schema-form/widgets/select.tsx +105 -0
  176. package/src/custom/schema-form/widgets/selectable.tsx +25 -0
  177. package/src/custom/schema-form/widgets/string-array.tsx +296 -0
  178. package/src/custom/schema-form/widgets/url.tsx +56 -0
  179. package/src/custom/section-layout-v2.tsx +212 -0
  180. package/src/custom/select-tabs.tsx +109 -0
  181. package/src/custom/selectable.tsx +316 -0
  182. package/src/custom/stepper.tsx +236 -0
  183. package/src/custom/tab-layout.tsx +213 -0
  184. package/src/custom/tanstack-table/fields/index.tsx +12 -0
  185. package/src/custom/tanstack-table/fields/tanstack-table-action-dialogs.tsx +89 -0
  186. package/src/custom/tanstack-table/fields/tanstack-table-column-header.tsx +66 -0
  187. package/src/custom/tanstack-table/fields/tanstack-table-filter-date.tsx +180 -0
  188. package/src/custom/tanstack-table/fields/tanstack-table-filter-faceted.tsx +158 -0
  189. package/src/custom/tanstack-table/fields/tanstack-table-filter-text.tsx +76 -0
  190. package/src/custom/tanstack-table/fields/tanstack-table-pagination.tsx +136 -0
  191. package/src/custom/tanstack-table/fields/tanstack-table-plain-table.tsx +142 -0
  192. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-confirmation.tsx +77 -0
  193. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-custom-dialog.tsx +87 -0
  194. package/src/custom/tanstack-table/fields/tanstack-table-row-actions.tsx +151 -0
  195. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-custom-dialog.tsx +88 -0
  196. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-schemaform-dialog.tsx +47 -0
  197. package/src/custom/tanstack-table/fields/tanstack-table-toolbar.tsx +143 -0
  198. package/src/custom/tanstack-table/fields/tanstack-table-view-options.tsx +171 -0
  199. package/src/custom/tanstack-table/index.tsx +244 -0
  200. package/src/custom/tanstack-table/types/index.ts +328 -0
  201. package/src/custom/tanstack-table/utils/cell-with-actions.tsx +21 -0
  202. package/src/custom/tanstack-table/utils/column-names.ts +26 -0
  203. package/src/custom/tanstack-table/utils/columns-by-row-data.tsx +312 -0
  204. package/src/custom/tanstack-table/utils/editable-columns-by-row-data.tsx +219 -0
  205. package/src/custom/tanstack-table/utils/faceted-boolean-options.tsx +22 -0
  206. package/src/custom/tanstack-table/utils/index.tsx +10 -0
  207. package/src/custom/tanstack-table/utils/pinning-styles.ts +57 -0
  208. package/src/custom/tanstack-table/utils/table.tsx +83 -0
  209. package/src/custom/tanstack-table/utils/test-conditions.ts +17 -0
  210. package/src/custom/timeline.tsx +208 -0
  211. package/src/custom/tree.tsx +200 -0
  212. package/src/custom/tscanify/browser.ts +66 -0
  213. package/src/custom/tscanify/index.ts +51 -0
  214. package/src/custom/tscanify/tscanify-browser.ts +522 -0
  215. package/src/custom/tscanify/tscanify.ts +262 -0
  216. package/src/custom/tscanify/types.ts +22 -0
  217. package/src/custom/webcam.tsx +737 -0
  218. package/src/hooks/.gitkeep +0 -0
  219. package/src/hooks/use-callback-ref.ts +27 -0
  220. package/src/hooks/use-controllable-state.ts +67 -0
  221. package/src/hooks/use-debounce.ts +19 -0
  222. package/src/hooks/use-is-visible.ts +23 -0
  223. package/src/hooks/use-media-query.ts +21 -0
  224. package/src/hooks/use-mobile.ts +21 -0
  225. package/src/hooks/use-on-window-resize.ts +15 -0
  226. package/src/hooks/use-scroll.tsx +22 -0
  227. package/src/lib/utils.ts +61 -0
  228. package/src/lib/zod.ts +2 -0
  229. package/src/styles/core.css +57 -0
  230. package/src/styles/globals.css +130 -0
  231. package/src/test/email-input.test.tsx +217 -0
  232. package/src/test/password-input.test.tsx +92 -0
  233. package/src/test/select-tabs.test.tsx +302 -0
  234. package/src/test/selectable.test.tsx +1093 -0
  235. package/tsconfig.json +13 -0
  236. package/tsconfig.lint.json +8 -0
@@ -0,0 +1,306 @@
1
+ import type { Column, ColumnDef, Row, Header } from "@tanstack/react-table";
2
+ import { HeaderCell, CellRenderer } from "../components/table";
3
+ import type {
4
+ ColumnConfig,
5
+ CustomRenderers,
6
+ GeneratedColumn,
7
+ JSONSchema,
8
+ JSONSchemaProperty,
9
+ Localization,
10
+ MasterDataGridResources,
11
+ } from "../types";
12
+ import { getFilterOperators, masterFilter } from "./filter-fns";
13
+ import { getColumnName } from "./translation-utils";
14
+ import { GenericObjectType } from "@rjsf/utils";
15
+
16
+ export function generateColumnsFromSchema<TData = unknown>(
17
+ schema: JSONSchema | GenericObjectType,
18
+ localization: Localization,
19
+ t?: MasterDataGridResources,
20
+ editingContext?: {
21
+ editingRows: Record<string, Record<string, unknown>>;
22
+ onCellUpdate: (rowId: string, columnId: string, value: unknown) => void;
23
+ getRowId: (row: TData, index: number) => string;
24
+ },
25
+ cellClassName?: string | ((cell: { row: TData; columnId: string }) => string),
26
+ dateOptions?: Intl.DateTimeFormatOptions,
27
+ customRenderers?: CustomRenderers<TData>,
28
+ errorDisplayMode?: "tooltip" | "inline" | "both",
29
+ enableColumnVisibility?: boolean,
30
+ expanderColumns?: Array<keyof TData> | Array<string>
31
+ ): GeneratedColumn<TData>[] {
32
+ if (!schema.properties) return [];
33
+
34
+ const columns: GeneratedColumn<TData>[] = [];
35
+
36
+ Object.entries(schema.properties).forEach(([key, property]) => {
37
+ const column = createColumnFromProperty<TData>(
38
+ key,
39
+ property as JSONSchemaProperty,
40
+ localization,
41
+ t,
42
+ editingContext,
43
+ cellClassName,
44
+ dateOptions,
45
+ customRenderers,
46
+ errorDisplayMode,
47
+ enableColumnVisibility,
48
+ expanderColumns
49
+ );
50
+ if (column) {
51
+ columns.push(column);
52
+ }
53
+ });
54
+
55
+ return columns;
56
+ }
57
+
58
+ function createColumnFromProperty<TData = unknown>(
59
+ key: string,
60
+ property: JSONSchemaProperty,
61
+ localization: Localization,
62
+ t?: MasterDataGridResources,
63
+ editingContext?: {
64
+ editingRows: Record<string, Record<string, unknown>>;
65
+ onCellUpdate: (rowId: string, columnId: string, value: unknown) => void;
66
+ getRowId: (row: TData, index: number) => string;
67
+ },
68
+ cellClassName?: string | ((cell: { row: TData; columnId: string }) => string),
69
+ dateOptions?: Intl.DateTimeFormatOptions,
70
+ customRenderers?: CustomRenderers<TData>,
71
+ errorDisplayMode?: "tooltip" | "inline" | "both",
72
+ enableColumnVisibility?: boolean,
73
+ expanderColumns?: Array<keyof TData> | Array<string>
74
+ ): GeneratedColumn<TData> | null {
75
+ if (property.type === "object" || property.type === "array") {
76
+ return null;
77
+ }
78
+
79
+ const filterOperators = getFilterOperators(property.type, property.format);
80
+
81
+ return {
82
+ id: key,
83
+ accessorKey: key,
84
+ header: ({
85
+ column,
86
+ header,
87
+ }: {
88
+ column: Column<TData>;
89
+ header: Header<TData, unknown>;
90
+ }) => (
91
+ <HeaderCell<TData>
92
+ column={column}
93
+ header={header}
94
+ label={getColumnName(key, t, property.title)}
95
+ t={t}
96
+ />
97
+ ),
98
+ cell: ({
99
+ getValue,
100
+ row,
101
+ column,
102
+ }: {
103
+ getValue: () => unknown;
104
+ row: Row<TData>;
105
+ column: Column<TData>;
106
+ }) => {
107
+ const rowId =
108
+ editingContext?.getRowId(row.original, row.index) || String(row.index);
109
+ const isEditing = editingContext?.editingRows[rowId] !== undefined;
110
+ const editedValue = editingContext?.editingRows[rowId]?.[key];
111
+ const displayValue =
112
+ isEditing && editedValue !== undefined ? editedValue : getValue();
113
+
114
+ const className =
115
+ typeof cellClassName === "function"
116
+ ? cellClassName({ row: row.original, columnId: key })
117
+ : cellClassName;
118
+
119
+ return (
120
+ <CellRenderer
121
+ value={displayValue}
122
+ row={row}
123
+ column={column}
124
+ columnId={key}
125
+ schemaProperty={property}
126
+ t={t}
127
+ isEditing={isEditing}
128
+ onUpdate={
129
+ isEditing
130
+ ? (value: unknown) =>
131
+ editingContext?.onCellUpdate(rowId, key, value)
132
+ : undefined
133
+ }
134
+ className={className}
135
+ dateOptions={dateOptions}
136
+ localization={localization}
137
+ fieldName={key as keyof TData & string}
138
+ customRenderers={customRenderers}
139
+ errorDisplayMode={errorDisplayMode}
140
+ />
141
+ );
142
+ },
143
+ enableSorting: !property.readOnly,
144
+ enableFiltering: !property.readOnly,
145
+ enableHiding: enableColumnVisibility ?? true,
146
+ filterFn: masterFilter,
147
+ meta: {
148
+ schemaProperty: property,
149
+ filterOperators,
150
+ isExpanderColumn:
151
+ expanderColumns?.includes(key as keyof TData & string) ?? false,
152
+ },
153
+ } as GeneratedColumn<TData>;
154
+ }
155
+
156
+ export function mergeColumns<TData = unknown>(
157
+ schemaColumns: GeneratedColumn<TData>[],
158
+ customColumns?: ColumnConfig<TData>[],
159
+ editingContext?: {
160
+ readonly editingRows: Record<string, Record<string, unknown>>;
161
+ getRowId: (row: TData, index: number) => string;
162
+ },
163
+ enableColumnVisibility?: boolean,
164
+ t?: MasterDataGridResources
165
+ ): ColumnDef<TData>[] {
166
+ if (!customColumns || customColumns.length === 0) {
167
+ return schemaColumns;
168
+ }
169
+
170
+ const merged: ColumnDef<TData>[] = [];
171
+ const customColumnMap = new Map(customColumns.map((c) => [c.id, c]));
172
+
173
+ schemaColumns.forEach((schemaCol) => {
174
+ if (!schemaCol.id) return;
175
+
176
+ const custom = customColumnMap.get(schemaCol.id);
177
+
178
+ if (custom) {
179
+ const customCell = custom.cell;
180
+ const schemaCell = schemaCol.cell;
181
+
182
+ let finalCell = customCell || schemaCell;
183
+
184
+ if (
185
+ customCell &&
186
+ schemaCell &&
187
+ typeof schemaCell === "function" &&
188
+ editingContext
189
+ ) {
190
+ finalCell = (props) => {
191
+ const rowId =
192
+ editingContext.getRowId(props.row.original, props.row.index) ||
193
+ String(props.row.index);
194
+ const isEditing = editingContext.editingRows[rowId] !== undefined;
195
+
196
+ if (isEditing) {
197
+ return typeof schemaCell === "function"
198
+ ? schemaCell(props)
199
+ : schemaCell;
200
+ }
201
+
202
+ return typeof customCell === "function"
203
+ ? customCell(props)
204
+ : customCell;
205
+ };
206
+ }
207
+
208
+ let finalHeader = custom.header || schemaCol.header;
209
+
210
+ if (
211
+ custom.header &&
212
+ custom.extendHeader !== false &&
213
+ typeof custom.header === "string"
214
+ ) {
215
+ finalHeader = ({
216
+ column,
217
+ header,
218
+ }: {
219
+ column: Column<TData>;
220
+ header: Header<TData, unknown>;
221
+ }) => (
222
+ <HeaderCell<TData>
223
+ column={column}
224
+ header={header}
225
+ label={custom.header as string}
226
+ t={t}
227
+ />
228
+ );
229
+ } else if (custom.header && custom.extendHeader === false) {
230
+ finalHeader = custom.header;
231
+ }
232
+
233
+ merged.push({
234
+ ...schemaCol,
235
+ ...custom,
236
+ header: finalHeader,
237
+ cell: finalCell,
238
+ enableHiding: custom.enableHiding ?? enableColumnVisibility ?? true,
239
+ meta: {
240
+ ...schemaCol.meta,
241
+ ...custom.meta,
242
+ },
243
+ } as ColumnDef<TData>);
244
+ if (schemaCol.id) customColumnMap.delete(schemaCol.id);
245
+ } else {
246
+ merged.push(schemaCol);
247
+ }
248
+ });
249
+
250
+ customColumnMap.forEach((custom) => {
251
+ let header:
252
+ | string
253
+ | ((info: {
254
+ column: Column<TData>;
255
+ header: Header<TData, unknown>;
256
+ }) => React.ReactNode);
257
+
258
+ if (custom.extendHeader !== false) {
259
+ header = ({
260
+ column,
261
+ header: headerObj,
262
+ }: {
263
+ column: Column<TData>;
264
+ header: Header<TData, unknown>;
265
+ }) => {
266
+ const label =
267
+ typeof custom.header === "string" ? custom.header : custom.id;
268
+
269
+ return (
270
+ <HeaderCell<TData>
271
+ column={column}
272
+ header={headerObj}
273
+ label={label}
274
+ t={t}
275
+ />
276
+ );
277
+ };
278
+ } else if (typeof custom.header === "function") {
279
+ header = custom.header;
280
+ } else {
281
+ header = custom.header || custom.id;
282
+ }
283
+
284
+ merged.push({
285
+ id: custom.id,
286
+ accessorKey: custom.accessorKey,
287
+ accessorFn: custom.accessorFn,
288
+ header,
289
+ cell: custom.cell,
290
+ enableSorting: custom.enableSorting ?? true,
291
+ enableFiltering: custom.enableFiltering ?? true,
292
+ enableGrouping: custom.enableGrouping ?? false,
293
+ enablePinning: custom.enablePinning ?? true,
294
+ enableResizing: custom.enableResizing ?? true,
295
+ enableHiding: custom.enableHiding ?? enableColumnVisibility ?? true,
296
+ size: custom.width,
297
+ minSize: custom.minWidth,
298
+ maxSize: custom.maxWidth,
299
+ footer: custom.footer,
300
+ filterFn: masterFilter,
301
+ meta: custom.meta,
302
+ } as ColumnDef<TData>);
303
+ });
304
+
305
+ return merged;
306
+ }
@@ -0,0 +1,67 @@
1
+ import type { Table } from "@tanstack/react-table";
2
+ import type { ExportColumnDef } from "../types";
3
+
4
+ export interface ExportOptions {
5
+ filename?: string;
6
+ }
7
+
8
+ export function exportToCSV<TData>(
9
+ table: Table<TData>,
10
+ options: ExportOptions = {}
11
+ ): void {
12
+ const { filename = "export" } = options;
13
+
14
+ const rows = table.getFilteredRowModel().rows;
15
+
16
+ const excludedColumns = ["expander", "select", "actions", "edit-actions"];
17
+ const columns = table
18
+ .getVisibleLeafColumns()
19
+ .filter((col) => !excludedColumns.includes(col.id));
20
+
21
+ const headers = columns.map((col) => {
22
+ const header = col.columnDef.header;
23
+ return typeof header === "string" ? header : col.id;
24
+ });
25
+
26
+ const csv = [
27
+ headers.join(","),
28
+ ...rows.map((row) =>
29
+ columns
30
+ .map((col) => {
31
+ const columnDef = col.columnDef as ExportColumnDef<TData>;
32
+ let value: unknown;
33
+
34
+ if (columnDef.accessorKey) {
35
+ const keys = String(columnDef.accessorKey).split(".");
36
+ value = keys.reduce(
37
+ (obj: unknown, key) =>
38
+ obj && typeof obj === "object" && key in obj
39
+ ? (obj as Record<string, unknown>)[key]
40
+ : undefined,
41
+ row.original
42
+ );
43
+ } else if (columnDef.accessorFn) {
44
+ value = columnDef.accessorFn(row.original, row.index);
45
+ } else {
46
+ value = row.getValue(col.id);
47
+ }
48
+ const strValue = String(value ?? "");
49
+ return strValue.includes(",") || strValue.includes('"')
50
+ ? `"${strValue.replace(/"/g, '""')}"`
51
+ : strValue;
52
+ })
53
+ .join(",")
54
+ ),
55
+ ].join("\n");
56
+
57
+ const csvWithBOM = "\uFEFF" + csv;
58
+ const blob = new Blob([csvWithBOM], {
59
+ type: "text/csv;charset=utf-8;",
60
+ });
61
+ const url = URL.createObjectURL(blob);
62
+ const link = document.createElement("a");
63
+ link.href = url;
64
+ link.download = `${filename}.csv`;
65
+ link.click();
66
+ URL.revokeObjectURL(url);
67
+ }
@@ -0,0 +1,290 @@
1
+ import type { FilterFn } from "@tanstack/react-table";
2
+ import type { FilterOperator } from "../types";
3
+
4
+ function getRowValue(row: unknown, columnId: string): unknown {
5
+ if (!row || typeof row !== "object") return undefined;
6
+
7
+ const keys = columnId.split(".");
8
+ let value: unknown = row;
9
+
10
+ for (const key of keys) {
11
+ if (value && typeof value === "object" && key in value) {
12
+ value = (value as Record<string, unknown>)[key];
13
+ } else {
14
+ return undefined;
15
+ }
16
+ }
17
+
18
+ return value;
19
+ }
20
+
21
+ function toString(value: unknown): string {
22
+ if (value === null || value === undefined) return "";
23
+ if (typeof value === "string") return value;
24
+ if (typeof value === "number" || typeof value === "boolean")
25
+ return String(value);
26
+ if (value instanceof Date) return value.toISOString();
27
+ if (typeof value === "object") return JSON.stringify(value);
28
+ return String(value);
29
+ }
30
+
31
+ function toNumber(value: unknown): number {
32
+ if (typeof value === "number") return value;
33
+ if (typeof value === "string") return parseFloat(value);
34
+ if (value instanceof Date) return value.getTime();
35
+ return NaN;
36
+ }
37
+
38
+ function toDate(value: unknown): Date | null {
39
+ if (value instanceof Date) return value;
40
+ if (typeof value === "string" || typeof value === "number") {
41
+ const date = new Date(value);
42
+ return isNaN(date.getTime()) ? null : date;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ export const masterFilter: FilterFn<unknown> = (row, columnId, filterValue) => {
48
+ if (!filterValue || typeof filterValue !== "object") return true;
49
+
50
+ const { operator, value, value2 } = filterValue as {
51
+ operator: FilterOperator;
52
+ value: unknown;
53
+ value2?: unknown;
54
+ };
55
+
56
+ const cellValue = getRowValue(row.original, columnId);
57
+
58
+ switch (operator) {
59
+ case "equals":
60
+ return (
61
+ toString(cellValue).toLowerCase() === toString(value).toLowerCase()
62
+ );
63
+
64
+ case "notEquals":
65
+ return (
66
+ toString(cellValue).toLowerCase() !== toString(value).toLowerCase()
67
+ );
68
+
69
+ case "contains":
70
+ return toString(cellValue)
71
+ .toLowerCase()
72
+ .includes(toString(value).toLowerCase());
73
+
74
+ case "notContains":
75
+ return !toString(cellValue)
76
+ .toLowerCase()
77
+ .includes(toString(value).toLowerCase());
78
+
79
+ case "startsWith":
80
+ return toString(cellValue)
81
+ .toLowerCase()
82
+ .startsWith(toString(value).toLowerCase());
83
+
84
+ case "endsWith":
85
+ return toString(cellValue)
86
+ .toLowerCase()
87
+ .endsWith(toString(value).toLowerCase());
88
+
89
+ case "isEmpty":
90
+ return !cellValue || toString(cellValue).trim() === "";
91
+
92
+ case "isNotEmpty":
93
+ return Boolean(cellValue) && toString(cellValue).trim() !== "";
94
+
95
+ case "greaterThan": {
96
+ const numValue = toNumber(cellValue);
97
+ const numFilter = toNumber(value);
98
+ return !isNaN(numValue) && !isNaN(numFilter) && numValue > numFilter;
99
+ }
100
+
101
+ case "greaterThanOrEqual": {
102
+ const numValue = toNumber(cellValue);
103
+ const numFilter = toNumber(value);
104
+ return !isNaN(numValue) && !isNaN(numFilter) && numValue >= numFilter;
105
+ }
106
+
107
+ case "lessThan": {
108
+ const numValue = toNumber(cellValue);
109
+ const numFilter = toNumber(value);
110
+ return !isNaN(numValue) && !isNaN(numFilter) && numValue < numFilter;
111
+ }
112
+
113
+ case "lessThanOrEqual": {
114
+ const numValue = toNumber(cellValue);
115
+ const numFilter = toNumber(value);
116
+ return !isNaN(numValue) && !isNaN(numFilter) && numValue <= numFilter;
117
+ }
118
+
119
+ case "between": {
120
+ const numValue = toNumber(cellValue);
121
+ const numMin = toNumber(value);
122
+ const numMax = toNumber(value2);
123
+ return (
124
+ !isNaN(numValue) &&
125
+ !isNaN(numMin) &&
126
+ !isNaN(numMax) &&
127
+ numValue >= numMin &&
128
+ numValue <= numMax
129
+ );
130
+ }
131
+
132
+ case "inRange": {
133
+ const numValue = toNumber(cellValue);
134
+ const numMin = toNumber(value);
135
+ const numMax = toNumber(value2);
136
+ return (
137
+ !isNaN(numValue) &&
138
+ !isNaN(numMin) &&
139
+ !isNaN(numMax) &&
140
+ numValue >= numMin &&
141
+ numValue <= numMax
142
+ );
143
+ }
144
+
145
+ case "before": {
146
+ const dateValue = toDate(cellValue);
147
+ const dateFilter = toDate(value);
148
+ return (
149
+ dateValue !== null && dateFilter !== null && dateValue < dateFilter
150
+ );
151
+ }
152
+
153
+ case "after": {
154
+ const dateValue = toDate(cellValue);
155
+ const dateFilter = toDate(value);
156
+ return (
157
+ dateValue !== null && dateFilter !== null && dateValue > dateFilter
158
+ );
159
+ }
160
+
161
+ case "inList": {
162
+ if (!Array.isArray(value)) return false;
163
+ const strValue = toString(cellValue).toLowerCase();
164
+ return value.some((v) => toString(v).toLowerCase() === strValue);
165
+ }
166
+
167
+ case "notInList": {
168
+ if (!Array.isArray(value)) return true;
169
+ const strValue = toString(cellValue).toLowerCase();
170
+ return !value.some((v) => toString(v).toLowerCase() === strValue);
171
+ }
172
+
173
+ default:
174
+ return true;
175
+ }
176
+ };
177
+
178
+ export function getFilterOperators(
179
+ type?: string,
180
+ format?: string
181
+ ): FilterOperator[] {
182
+ if (format === "date" || format === "date-time" || format === "time") {
183
+ return [
184
+ "equals",
185
+ "notEquals",
186
+ "before",
187
+ "after",
188
+ "between",
189
+ "isEmpty",
190
+ "isNotEmpty",
191
+ ];
192
+ }
193
+
194
+ if (type === "number" || type === "integer") {
195
+ return [
196
+ "equals",
197
+ "notEquals",
198
+ "greaterThan",
199
+ "greaterThanOrEqual",
200
+ "lessThan",
201
+ "lessThanOrEqual",
202
+ "between",
203
+ "inRange",
204
+ "isEmpty",
205
+ "isNotEmpty",
206
+ ];
207
+ }
208
+
209
+ if (type === "boolean") {
210
+ return ["equals", "notEquals", "isEmpty", "isNotEmpty"];
211
+ }
212
+
213
+ if (format === "enum") {
214
+ return [
215
+ "equals",
216
+ "notEquals",
217
+ "inList",
218
+ "notInList",
219
+ "isEmpty",
220
+ "isNotEmpty",
221
+ ];
222
+ }
223
+
224
+ return [
225
+ "equals",
226
+ "notEquals",
227
+ "contains",
228
+ "notContains",
229
+ "startsWith",
230
+ "endsWith",
231
+ "isEmpty",
232
+ "isNotEmpty",
233
+ ];
234
+ }
235
+
236
+ export function validateFilterValue(
237
+ operator: FilterOperator,
238
+ value: unknown,
239
+ value2?: unknown
240
+ ): boolean {
241
+ if (operator === "isEmpty" || operator === "isNotEmpty") {
242
+ return true;
243
+ }
244
+
245
+ if (operator === "between" || operator === "inRange") {
246
+ return (
247
+ value !== undefined &&
248
+ value !== null &&
249
+ value !== "" &&
250
+ value2 !== undefined &&
251
+ value2 !== null &&
252
+ value2 !== ""
253
+ );
254
+ }
255
+
256
+ if (operator === "inList" || operator === "notInList") {
257
+ return Array.isArray(value) && value.length > 0;
258
+ }
259
+
260
+ return value !== undefined && value !== null && value !== "";
261
+ }
262
+
263
+ export function formatFilterValue(
264
+ value: unknown,
265
+ operator: FilterOperator,
266
+ schemaType?: string,
267
+ schemaFormat?: string
268
+ ): string {
269
+ if (value === null || value === undefined) return "";
270
+
271
+ if (Array.isArray(value)) {
272
+ return value.map((v) => toString(v)).join(", ");
273
+ }
274
+
275
+ if (schemaFormat === "date" || schemaFormat === "date-time") {
276
+ const date = toDate(value);
277
+ if (date) {
278
+ return schemaFormat === "date"
279
+ ? date.toLocaleDateString()
280
+ : date.toLocaleString();
281
+ }
282
+ }
283
+
284
+ if (schemaType === "number" || schemaType === "integer") {
285
+ const num = toNumber(value);
286
+ return isNaN(num) ? toString(value) : num.toString();
287
+ }
288
+
289
+ return toString(value);
290
+ }
@@ -0,0 +1,8 @@
1
+ export {
2
+ getPinningHeaderStyles,
3
+ getPinningHeaderClassNames,
4
+ getPinningCellStyles,
5
+ getPinningCellClassNames,
6
+ } from "./pinning-utils";
7
+
8
+ export { getTranslations, getColumnName } from "./translation-utils";