@teamprodevs/appsmith-custom-table 1.1.4 → 1.1.5
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 +514 -65
- package/dist/app.js +1 -1
- package/dist/app.umd.cjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,33 +3,56 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@teamprodevs/appsmith-custom-table)
|
|
4
4
|
[](#license)
|
|
5
5
|
[](https://custom-appsmith-table.netlify.app/)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
6
7
|
|
|
7
|
-
A highly configurable table
|
|
8
|
+
A highly configurable table component built for Appsmith custom widgets. It combines React 18, TanStack Table v8, and TailwindCSS to deliver a powerful client-side table that integrates seamlessly with Appsmith's data sources including PostgreSQL, MongoDB, Elasticsearch, and REST APIs.
|
|
9
|
+
|
|
10
|
+
> ⚠️ **Maintenance Notice**: This project was developed as a job task and is **not actively maintained**. If you need additional features or bug fixes, please [fork this repository](https://github.com/smarts-uz/appsmith-custom-table/fork) and maintain your own version.
|
|
11
|
+
|
|
12
|
+
## 🔗 Quick Links
|
|
13
|
+
|
|
14
|
+
| Resource | Link |
|
|
15
|
+
|----------|------|
|
|
16
|
+
| 📚 **Storybook Demo** | [custom-appsmith-table.netlify.app](https://custom-appsmith-table.netlify.app/?path=/story/appsmith-table--translated-table) |
|
|
17
|
+
| 📦 **NPM Package** | [npmjs.com/package/@teamprodevs/appsmith-custom-table](https://www.npmjs.com/package/@teamprodevs/appsmith-custom-table) |
|
|
18
|
+
| 🎯 **Appsmith Example** | [Live Appsmith Demo](https://custom-table.appsmith.com/app/appsmith-custom-table/basic-example-695f8fe01bbc1832a1e36e11?environment=production) |
|
|
19
|
+
| 💻 **GitHub Repository** | [github.com/smarts-uz/appsmith-custom-table](https://github.com/smarts-uz/appsmith-custom-table) |
|
|
8
20
|
|
|
9
21
|
## Features
|
|
10
22
|
|
|
11
23
|
- Full Appsmith custom component support (bundled + CDN).
|
|
12
|
-
-
|
|
13
|
-
-
|
|
24
|
+
- Client-side pagination with infinite scroll support.
|
|
25
|
+
- Tight integration with Appsmith's data models (PostgreSQL, MongoDB, Elasticsearch, REST APIs).
|
|
26
|
+
- Typed configuration powered by Zod schemas for validation.
|
|
14
27
|
- Rich styling hooks with Tailwind-first tokenization.
|
|
15
28
|
- Action hooks, event callbacks, and controlled `updateModel` APIs.
|
|
16
|
-
-
|
|
29
|
+
- Conditional row styling based on cell values.
|
|
30
|
+
- Multi-language support (i18n) for column headers and action labels.
|
|
31
|
+
- Built-in formatters for phone, date, datetime, and currency.
|
|
32
|
+
- Compatible with pgrest/dbtorest pagination patterns.
|
|
17
33
|
|
|
18
34
|
## Table of Contents
|
|
19
35
|
|
|
20
|
-
1. [
|
|
36
|
+
1. [Quick Links](#-quick-links)
|
|
21
37
|
2. [Installation](#installation)
|
|
22
38
|
3. [CDN Usage](#cdn-usage)
|
|
23
39
|
4. [Quick Start](#quick-start)
|
|
24
40
|
5. [Usage](#usage)
|
|
25
|
-
6. [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
6. [API Reference](#api-reference)
|
|
42
|
+
- [TableModel Props](#tablemodel-props)
|
|
43
|
+
- [Column Schema](#column-schema)
|
|
44
|
+
- [Column Types](#column-types)
|
|
45
|
+
7. [Row Actions](#row-actions)
|
|
46
|
+
8. [Conditional Styling](#conditional-styling)
|
|
47
|
+
9. [Translations (i18n)](#translations-i18n)
|
|
48
|
+
10. [Customization](#customization)
|
|
49
|
+
- [Styles](#styles)
|
|
50
|
+
- [CSS Variables](#css-variables)
|
|
51
|
+
11. [Events](#events)
|
|
52
|
+
12. [Development](#development)
|
|
53
|
+
13. [Contributing](#contributing)
|
|
54
|
+
14. [License](#license)
|
|
55
|
+
15. [Acknowledgements](#acknowledgements)
|
|
33
56
|
|
|
34
57
|
## Demo
|
|
35
58
|
|
|
@@ -54,16 +77,18 @@ Ideal for Appsmith widgets where bundling is not available.
|
|
|
54
77
|
|
|
55
78
|
## Quick Start
|
|
56
79
|
|
|
57
|
-
1. Define a schema describing each column
|
|
58
|
-
2.
|
|
59
|
-
3.
|
|
80
|
+
1. Define a schema describing each column's type and display options.
|
|
81
|
+
2. Pass your Appsmith query data to the `ClientTable` component.
|
|
82
|
+
3. Wire up `triggerEvent` and `updateModel` callbacks to Appsmith's APIs.
|
|
83
|
+
4. Optionally add custom styles, actions, and conditional formatting.
|
|
60
84
|
|
|
61
85
|
## Usage
|
|
62
86
|
|
|
63
87
|
### Client-side Table
|
|
64
88
|
|
|
65
89
|
```tsx
|
|
66
|
-
import {
|
|
90
|
+
import { ClientTable } from "@teamprodevs/appsmith-custom-table";
|
|
91
|
+
import "@teamprodevs/appsmith-custom-table/dist/styles.css";
|
|
67
92
|
|
|
68
93
|
const data = [
|
|
69
94
|
{ id: 1, name: "Alice", age: 25 },
|
|
@@ -71,83 +96,468 @@ const data = [
|
|
|
71
96
|
];
|
|
72
97
|
|
|
73
98
|
const schema = {
|
|
74
|
-
id: { type: "text",
|
|
75
|
-
name: { type: "text",
|
|
76
|
-
age: { type: "
|
|
99
|
+
id: { type: "text", title: { en: "ID", uz: "ID" } },
|
|
100
|
+
name: { type: "text", title: { en: "Name", uz: "Ism" } },
|
|
101
|
+
age: { type: "text", title: { en: "Age", uz: "Yosh" } },
|
|
77
102
|
};
|
|
78
103
|
|
|
79
|
-
const
|
|
104
|
+
const MyTable = () => (
|
|
105
|
+
<ClientTable
|
|
106
|
+
tableData={data}
|
|
107
|
+
schema={schema}
|
|
108
|
+
locale="en"
|
|
109
|
+
triggerEvent={(event, payload) => console.log(event, payload)}
|
|
110
|
+
updateModel={(model) => console.log(model)}
|
|
111
|
+
onModelChange={(model) => console.log(model)}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
80
114
|
```
|
|
81
115
|
|
|
82
|
-
###
|
|
116
|
+
### Infinite Scroll with Appsmith
|
|
117
|
+
|
|
118
|
+
The table triggers `onLoadMore` events for pagination. Wire this to your Appsmith query:
|
|
83
119
|
|
|
84
120
|
```tsx
|
|
85
|
-
import {
|
|
121
|
+
import { ClientTable } from "@teamprodevs/appsmith-custom-table";
|
|
86
122
|
|
|
123
|
+
// In your Appsmith custom widget
|
|
87
124
|
const tableModel = {
|
|
88
|
-
|
|
89
|
-
url: "https://api.example.com/users",
|
|
90
|
-
method: "GET",
|
|
91
|
-
perPage: 20,
|
|
92
|
-
paginationKeys: { offset: "offset", limit: "limit" },
|
|
93
|
-
},
|
|
125
|
+
tableData: appsmith.model.queryData, // Data from your Appsmith query
|
|
94
126
|
schema,
|
|
95
|
-
|
|
127
|
+
locale: "en",
|
|
128
|
+
limit: 20,
|
|
129
|
+
max_count: appsmith.model.totalCount, // Total rows from your API
|
|
130
|
+
triggerEvent: (event, payload) => appsmith.triggerEvent(event, payload),
|
|
131
|
+
updateModel: (model) => appsmith.updateModel(model),
|
|
132
|
+
onModelChange: (model) => console.log("table state", model),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const UsersTable = () => <ClientTable {...tableModel} />;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## API Reference
|
|
139
|
+
|
|
140
|
+
### TableModel Props
|
|
141
|
+
|
|
142
|
+
The `ClientTable` component accepts the following props (all validated via Zod schemas):
|
|
143
|
+
|
|
144
|
+
| Prop | Type | Required | Default | Description |
|
|
145
|
+
|------|------|----------|---------|-------------|
|
|
146
|
+
| `tableData` | `any[]` | Yes | `[]` | Array of row data objects |
|
|
147
|
+
| `schema` | `Schema` | Yes | - | Column definitions (see [Column Schema](#column-schema)) |
|
|
148
|
+
| `locale` | `string` | Yes | - | Active language code for translations (e.g., `"en"`, `"uz"`, `"ru"`) |
|
|
149
|
+
| `triggerEvent` | `TriggerEvent` | Yes | - | Callback to trigger Appsmith events |
|
|
150
|
+
| `updateModel` | `UpdateModel` | Yes | - | Callback to update Appsmith model state |
|
|
151
|
+
| `onModelChange` | `OnModelChange` | Yes | - | Callback fired when table model changes |
|
|
152
|
+
| `limit` | `number` | No | `20` | Number of rows per page |
|
|
153
|
+
| `max_count` | `number` | No | `20` | Maximum total rows (for pagination) |
|
|
154
|
+
| `indexColumn` | `IndexColumn` | No | - | Configuration for row index column |
|
|
155
|
+
| `actionColumn` | `ActionColumn` | No | - | Configuration for action buttons column |
|
|
156
|
+
| `conditionalRowStyles` | `ConditionalRowStyle[]` | No | - | Rules for conditional row styling |
|
|
157
|
+
| `styles` | `AppsmithTableStyles` | No | - | Custom styling configuration |
|
|
158
|
+
| `rowSelectionAction` | `string` | No | - | Event name triggered on row selection |
|
|
159
|
+
|
|
160
|
+
### Column Schema
|
|
161
|
+
|
|
162
|
+
Each column in the `schema` object is defined with these options:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const schema = {
|
|
166
|
+
column_key: {
|
|
167
|
+
type: "text", // Column type (see Column Types)
|
|
168
|
+
size: "md", // Width: "xs" | "sm" | "md" | "lg"
|
|
169
|
+
title: { // Localized column headers
|
|
170
|
+
en: "English Title",
|
|
171
|
+
uz: "O'zbek Sarlavha",
|
|
172
|
+
ru: "Русский заголовок"
|
|
173
|
+
},
|
|
174
|
+
className: "custom-class" // Custom CSS classes
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Option | Type | Required | Default | Description |
|
|
180
|
+
|--------|------|----------|---------|-------------|
|
|
181
|
+
| `type` | `ColumnType` | No | `"text"` | Data type for formatting |
|
|
182
|
+
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | No | `"md"` | Column width preset |
|
|
183
|
+
| `title` | `Record<string, string>` | No | - | Localized headers by language code |
|
|
184
|
+
| `className` | `string` | No | - | Custom CSS classes for column |
|
|
185
|
+
|
|
186
|
+
### Column Types
|
|
187
|
+
|
|
188
|
+
The table supports 6 column types with automatic formatting:
|
|
189
|
+
|
|
190
|
+
| Type | Description | Example Output |
|
|
191
|
+
|------|-------------|----------------|
|
|
192
|
+
| `text` | Plain text display (default) | `"John Doe"` |
|
|
193
|
+
| `url` | Clickable link (special format) | `<a href="...">Display Text</a>` |
|
|
194
|
+
| `phone` | Phone number formatting | `99 123 45 67` |
|
|
195
|
+
| `date` | Date formatting | `15-03-2024` |
|
|
196
|
+
| `datetime` | Date and time formatting | `15-03-2024 14:30` |
|
|
197
|
+
| `currency` | Currency with thousand separators | `1 234 567` |
|
|
198
|
+
|
|
199
|
+
#### URL Column Format
|
|
200
|
+
|
|
201
|
+
For URL columns, use the special format `"Display Text|||https://url.com"`:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const data = [
|
|
205
|
+
{
|
|
206
|
+
link: "Visit Site|||https://example.com",
|
|
207
|
+
// Renders as clickable "Visit Site" link
|
|
208
|
+
}
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
const schema = {
|
|
212
|
+
link: { type: "url", title: { en: "Link" } }
|
|
96
213
|
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
When clicked, triggers `onRedirect` event with the URL.
|
|
217
|
+
|
|
218
|
+
## Row Actions
|
|
219
|
+
|
|
220
|
+
Add interactive action buttons to each row using the `actionColumn` configuration:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { ClientTable } from "@teamprodevs/appsmith-custom-table";
|
|
97
224
|
|
|
98
|
-
const
|
|
225
|
+
const tableModel = {
|
|
226
|
+
tableData: data,
|
|
227
|
+
schema: schema,
|
|
228
|
+
locale: "en",
|
|
229
|
+
actionColumn: {
|
|
230
|
+
enable: true,
|
|
231
|
+
pin: "right", // "left" | "right"
|
|
232
|
+
type: "outline", // Button variant
|
|
233
|
+
icon: "MoreVertical", // Lucide icon for dropdown trigger
|
|
234
|
+
actions: [
|
|
235
|
+
{
|
|
236
|
+
title: { en: "View", uz: "Ko'rish", ru: "Просмотр" },
|
|
237
|
+
onClick: "onView", // Event name to trigger
|
|
238
|
+
icon: "Eye", // Lucide icon name
|
|
239
|
+
className: "text-blue-600"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
title: { en: "Edit", uz: "Tahrirlash", ru: "Редактировать" },
|
|
243
|
+
onClick: "onEdit",
|
|
244
|
+
icon: "Pencil"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
title: { en: "Delete", uz: "O'chirish", ru: "Удалить" },
|
|
248
|
+
onClick: "onDelete",
|
|
249
|
+
icon: "Trash2",
|
|
250
|
+
className: "text-red-600"
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
triggerEvent: (event, payload) => {
|
|
255
|
+
// payload contains { row: <row data> }
|
|
256
|
+
console.log(event, payload);
|
|
257
|
+
},
|
|
258
|
+
// ... other props
|
|
259
|
+
};
|
|
99
260
|
```
|
|
100
261
|
|
|
101
|
-
|
|
262
|
+
### Action Column Options
|
|
263
|
+
|
|
264
|
+
| Option | Type | Required | Default | Description |
|
|
265
|
+
|--------|------|----------|---------|-------------|
|
|
266
|
+
| `enable` | `boolean` | Yes | - | Enable/disable action column |
|
|
267
|
+
| `actions` | `RowAction[]` | Yes | - | Array of action definitions |
|
|
268
|
+
| `pin` | `"left" \| "right"` | No | `"right"` | Pin column position |
|
|
269
|
+
| `type` | `string` | No | `"default"` | Button variant |
|
|
270
|
+
| `icon` | `LucideIconName` | No | - | Icon for dropdown trigger |
|
|
271
|
+
|
|
272
|
+
### Button Variants
|
|
102
273
|
|
|
103
|
-
|
|
274
|
+
Available button variants: `"default"`, `"destructive"`, `"outline"`, `"secondary"`, `"ghost"`, `"link"`
|
|
104
275
|
|
|
105
|
-
|
|
106
|
-
- **`FetcherSchema`**: Encapsulates REST config—method, headers, query/body params, pagination keys, debounce, and optimistic flags.
|
|
107
|
-
- **`TableModelSchema`**: The orchestration layer combining schema, fetcher, selection settings, actions, row styles, and callbacks.
|
|
276
|
+
### Supported Icons
|
|
108
277
|
|
|
109
|
-
|
|
278
|
+
All [Lucide React](https://lucide.dev/icons/) icons are supported. Use the icon name as a string (e.g., `"Eye"`, `"Pencil"`, `"Trash2"`, `"Activity"`, `"AlarmClockPlus"`).
|
|
279
|
+
|
|
280
|
+
## Conditional Styling
|
|
281
|
+
|
|
282
|
+
Apply dynamic styles to rows based on cell values using `conditionalRowStyles`:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const tableModel = {
|
|
286
|
+
// ... other props
|
|
287
|
+
conditionalRowStyles: [
|
|
288
|
+
// Highlight rows where used_days >= 150
|
|
289
|
+
{
|
|
290
|
+
column: "used_days",
|
|
291
|
+
operator: ">=",
|
|
292
|
+
value: 150,
|
|
293
|
+
className: "bg-yellow-200"
|
|
294
|
+
},
|
|
295
|
+
// Red background for used_days >= 300
|
|
296
|
+
{
|
|
297
|
+
column: "used_days",
|
|
298
|
+
operator: ">=",
|
|
299
|
+
value: 300,
|
|
300
|
+
className: "bg-red-400"
|
|
301
|
+
},
|
|
302
|
+
// Compare two columns: highlight when payment < debt
|
|
303
|
+
{
|
|
304
|
+
column: "total_payment",
|
|
305
|
+
operator: "<",
|
|
306
|
+
value: { columnRef: "debt_amount" },
|
|
307
|
+
className: "text-red-800 font-bold"
|
|
308
|
+
},
|
|
309
|
+
// Green when payment >= debt
|
|
310
|
+
{
|
|
311
|
+
column: "total_payment",
|
|
312
|
+
operator: ">=",
|
|
313
|
+
value: { columnRef: "debt_amount" },
|
|
314
|
+
className: "text-green-800 font-bold"
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
};
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Conditional Style Options
|
|
321
|
+
|
|
322
|
+
| Option | Type | Required | Description |
|
|
323
|
+
|--------|------|----------|-------------|
|
|
324
|
+
| `column` | `string` | Yes | Column key to evaluate |
|
|
325
|
+
| `operator` | `RowStyleOperator` | Yes | Comparison operator |
|
|
326
|
+
| `value` | `string \| number \| boolean \| { columnRef: string }` | Yes | Value to compare against (or another column) |
|
|
327
|
+
| `className` | `string` | Yes | Tailwind/CSS classes to apply |
|
|
328
|
+
|
|
329
|
+
### Supported Operators
|
|
330
|
+
|
|
331
|
+
| Operator | Description |
|
|
332
|
+
|----------|-------------|
|
|
333
|
+
| `>` | Greater than |
|
|
334
|
+
| `<` | Less than |
|
|
335
|
+
| `>=` | Greater than or equal |
|
|
336
|
+
| `<=` | Less than or equal |
|
|
337
|
+
| `===` | Strict equality |
|
|
338
|
+
| `==` | Loose equality |
|
|
339
|
+
| `!==` | Strict inequality |
|
|
340
|
+
| `!=` | Loose inequality |
|
|
341
|
+
| `contains` | String contains |
|
|
342
|
+
| `startsWith` | String starts with |
|
|
343
|
+
| `endsWith` | String ends with |
|
|
344
|
+
| `isEmpty` | Value is empty |
|
|
345
|
+
| `isNotEmpty` | Value is not empty |
|
|
346
|
+
|
|
347
|
+
### Column-to-Column Comparison
|
|
348
|
+
|
|
349
|
+
Use `{ columnRef: "column_name" }` to compare against another column's value:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
{
|
|
353
|
+
column: "actual_amount",
|
|
354
|
+
operator: "<",
|
|
355
|
+
value: { columnRef: "expected_amount" },
|
|
356
|
+
className: "text-red-600"
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Translations (i18n)
|
|
361
|
+
|
|
362
|
+
The table supports multi-language column headers and action labels:
|
|
363
|
+
|
|
364
|
+
### Column Header Translations
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
const schema = {
|
|
368
|
+
customer_name: {
|
|
369
|
+
title: {
|
|
370
|
+
en: "Customer Name",
|
|
371
|
+
uz: "Mijoz Ismi",
|
|
372
|
+
ru: "Имя клиента"
|
|
373
|
+
},
|
|
374
|
+
type: "text"
|
|
375
|
+
},
|
|
376
|
+
phone: {
|
|
377
|
+
title: {
|
|
378
|
+
en: "Phone Number",
|
|
379
|
+
uz: "Telefon Raqam",
|
|
380
|
+
ru: "Телефон номер"
|
|
381
|
+
},
|
|
382
|
+
type: "phone"
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// Set active language
|
|
387
|
+
<ClientTable
|
|
388
|
+
schema={schema}
|
|
389
|
+
locale="uz" // Shows "Mijoz Ismi", "Telefon Raqam"
|
|
390
|
+
// ...
|
|
391
|
+
/>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Action Label Translations
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
const actionColumn = {
|
|
398
|
+
enable: true,
|
|
399
|
+
actions: [
|
|
400
|
+
{
|
|
401
|
+
title: {
|
|
402
|
+
en: "View Details",
|
|
403
|
+
uz: "Batafsil ko'rish",
|
|
404
|
+
ru: "Посмотреть детали"
|
|
405
|
+
},
|
|
406
|
+
onClick: "onView",
|
|
407
|
+
icon: "Eye"
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
};
|
|
411
|
+
```
|
|
110
412
|
|
|
111
413
|
## Customization
|
|
112
414
|
|
|
113
415
|
### Styles
|
|
114
416
|
|
|
417
|
+
Apply custom styles to different parts of the table:
|
|
418
|
+
|
|
115
419
|
```tsx
|
|
116
|
-
import {
|
|
117
|
-
|
|
118
|
-
AppsmithTableStyles,
|
|
119
|
-
} from "@teamprodevs/appsmith-custom-table";
|
|
420
|
+
import { ClientTable } from "@teamprodevs/appsmith-custom-table";
|
|
421
|
+
import type { AppsmithTableStyles } from "@teamprodevs/appsmith-custom-table";
|
|
120
422
|
|
|
121
423
|
const styles: AppsmithTableStyles = {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
424
|
+
container: "bg-white shadow-md rounded-lg px-1",
|
|
425
|
+
table: "border border-gray-200",
|
|
426
|
+
head: {
|
|
427
|
+
body: "bg-gray-100",
|
|
428
|
+
row: "hover:bg-gray-200 transition-colors",
|
|
429
|
+
cell: "border-b border-gray-300 font-semibold"
|
|
430
|
+
},
|
|
431
|
+
body: {
|
|
432
|
+
body: "bg-white",
|
|
433
|
+
row: "odd:bg-gray-50 even:bg-white hover:bg-blue-50",
|
|
434
|
+
cell: "border-b border-gray-200 px-3 py-2"
|
|
435
|
+
}
|
|
126
436
|
};
|
|
127
437
|
|
|
128
438
|
const StyledTable = () => (
|
|
129
|
-
<
|
|
439
|
+
<ClientTable
|
|
440
|
+
schema={schema}
|
|
441
|
+
tableData={data}
|
|
442
|
+
locale="en"
|
|
443
|
+
styles={styles}
|
|
444
|
+
// ...other props
|
|
445
|
+
/>
|
|
130
446
|
);
|
|
131
447
|
```
|
|
132
448
|
|
|
133
|
-
###
|
|
449
|
+
### Style Options
|
|
450
|
+
|
|
451
|
+
| Option | Type | Description |
|
|
452
|
+
|--------|------|-------------|
|
|
453
|
+
| `container` | `string` | Wrapper container classes |
|
|
454
|
+
| `table` | `string` | Table element classes |
|
|
455
|
+
| `head.body` | `string` | Table header body classes |
|
|
456
|
+
| `head.row` | `string` | Header row classes |
|
|
457
|
+
| `head.cell` | `string` | Header cell classes |
|
|
458
|
+
| `body.body` | `string` | Table body classes |
|
|
459
|
+
| `body.row` | `string` | Body row classes |
|
|
460
|
+
| `body.cell` | `string` | Body cell classes |
|
|
461
|
+
| `variables` | `Record<string, string>` | CSS custom properties |
|
|
134
462
|
|
|
135
|
-
|
|
136
|
-
- Trigger events with contextual payloads for Appsmith event handlers.
|
|
137
|
-
- Consume `updateModel` to keep external state in sync with table interactions.
|
|
463
|
+
### CSS Variables
|
|
138
464
|
|
|
139
|
-
|
|
465
|
+
Use CSS variables for theming with design tokens:
|
|
140
466
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
-
|
|
467
|
+
```typescript
|
|
468
|
+
const styles: AppsmithTableStyles = {
|
|
469
|
+
head: {
|
|
470
|
+
body: "bg-[var(--primary)] text-[var(--primary-foreground)]",
|
|
471
|
+
row: "hover:bg-[var(--primary-foreground)] hover:text-[var(--primary)]",
|
|
472
|
+
cell: "border-b border-[var(--border)]"
|
|
473
|
+
},
|
|
474
|
+
body: {
|
|
475
|
+
body: "bg-[var(--card)] text-[var(--card-foreground)]",
|
|
476
|
+
row: "odd:bg-[var(--accent)] even:bg-[var(--card)] hover:bg-[var(--muted)]",
|
|
477
|
+
cell: "border-b border-[var(--border)]"
|
|
478
|
+
},
|
|
479
|
+
container: "bg-[var(--card)] shadow-md rounded-lg px-1",
|
|
480
|
+
variables: {
|
|
481
|
+
"--primary": "hsl(220 70% 50%)",
|
|
482
|
+
"--primary-foreground": "hsl(0 0% 100%)",
|
|
483
|
+
"--card": "hsl(0 0% 100%)",
|
|
484
|
+
"--card-foreground": "hsl(0 0% 10%)",
|
|
485
|
+
"--border": "hsl(0 0% 90%)",
|
|
486
|
+
"--accent": "hsl(43 74% 66%)",
|
|
487
|
+
"--muted": "hsl(0 0% 96%)"
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
```
|
|
145
491
|
|
|
146
|
-
|
|
492
|
+
### Index Column
|
|
147
493
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
494
|
+
Add a row index column:
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
const tableModel = {
|
|
498
|
+
// ...
|
|
499
|
+
indexColumn: {
|
|
500
|
+
enable: true,
|
|
501
|
+
pin: "left", // "left" | "right"
|
|
502
|
+
className: "bg-gray-100 font-mono"
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## Events
|
|
508
|
+
|
|
509
|
+
The table triggers events through the `triggerEvent` callback:
|
|
510
|
+
|
|
511
|
+
| Event | Payload | Description |
|
|
512
|
+
|-------|---------|-------------|
|
|
513
|
+
| `onLoadMore` | `{ page, limit }` | Infinite scroll pagination request |
|
|
514
|
+
| `onRedirect` | `{ url }` | URL column click |
|
|
515
|
+
| `rowSelectionAction` | `{ row }` | Row selection (if configured) |
|
|
516
|
+
| Custom action events | `{ row }` | Row action button clicks |
|
|
517
|
+
|
|
518
|
+
### Example Event Handling in Appsmith
|
|
519
|
+
|
|
520
|
+
```javascript
|
|
521
|
+
// In your Appsmith custom widget
|
|
522
|
+
triggerEvent: (eventName, payload) => {
|
|
523
|
+
switch(eventName) {
|
|
524
|
+
case 'onView':
|
|
525
|
+
appsmith.triggerEvent('onRowView', { data: payload.row });
|
|
526
|
+
break;
|
|
527
|
+
case 'onEdit':
|
|
528
|
+
appsmith.triggerEvent('onRowEdit', { data: payload.row });
|
|
529
|
+
break;
|
|
530
|
+
case 'onDelete':
|
|
531
|
+
appsmith.triggerEvent('onRowDelete', { data: payload.row });
|
|
532
|
+
break;
|
|
533
|
+
case 'onLoadMore':
|
|
534
|
+
// Fetch next page
|
|
535
|
+
appsmith.triggerEvent('fetchNextPage', {
|
|
536
|
+
page: payload.page,
|
|
537
|
+
limit: payload.limit
|
|
538
|
+
});
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## Appsmith Integration
|
|
545
|
+
|
|
546
|
+
This table is designed for tight integration with Appsmith's ecosystem:
|
|
547
|
+
|
|
548
|
+
- **Data Sources**: Works with any Appsmith-supported data source (PostgreSQL, MongoDB, Elasticsearch, REST APIs, GraphQL)
|
|
549
|
+
- **Infinite Scroll**: Triggers `onLoadMore` events that you wire to Appsmith queries for pagination
|
|
550
|
+
- **Event System**: All actions flow through Appsmith's `triggerEvent` and `updateModel` APIs
|
|
551
|
+
- **Client-Side Rendering**: All rendering happens in the browser; Appsmith handles data fetching
|
|
552
|
+
- **pgrest/dbtorest Compatible**: Pagination parameters match common REST patterns
|
|
553
|
+
|
|
554
|
+
### How It Works
|
|
555
|
+
|
|
556
|
+
1. Your Appsmith query fetches data from any supported source
|
|
557
|
+
2. Data is passed to `ClientTable` via the `tableData` prop
|
|
558
|
+
3. User interactions trigger events (row clicks, actions, load more)
|
|
559
|
+
4. You handle events in Appsmith to update queries or trigger workflows
|
|
560
|
+
5. Updated data flows back to the table
|
|
151
561
|
|
|
152
562
|
## Development
|
|
153
563
|
|
|
@@ -156,18 +566,55 @@ const StyledTable = () => (
|
|
|
156
566
|
3. Add stories, ensure lint/tests pass, then open a PR.
|
|
157
567
|
|
|
158
568
|
```bash
|
|
159
|
-
git clone
|
|
569
|
+
git clone https://github.com/smarts-uz/appsmith-custom-table.git
|
|
160
570
|
cd appsmith-custom-table
|
|
161
571
|
npm install
|
|
162
572
|
npm run storybook
|
|
163
573
|
```
|
|
164
574
|
|
|
575
|
+
### Available Scripts
|
|
576
|
+
|
|
577
|
+
| Script | Description |
|
|
578
|
+
|--------|-------------|
|
|
579
|
+
| `npm run storybook` | Start Storybook dev server on port 6006 |
|
|
580
|
+
| `npm run build` | Build the library for production |
|
|
581
|
+
| `npm run build-storybook` | Build static Storybook site |
|
|
582
|
+
| `npm run lint` | Run ESLint |
|
|
583
|
+
|
|
165
584
|
## Contributing
|
|
166
585
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
586
|
+
> ⚠️ **Note**: This project is not actively maintained. It was created as a job task to solve a specific problem. If you need new features or extended functionality, **please fork this repository** and develop your own version.
|
|
587
|
+
|
|
588
|
+
### Forking This Project (Recommended)
|
|
589
|
+
|
|
590
|
+
Since this project is not actively maintained, forking is the recommended approach:
|
|
591
|
+
|
|
592
|
+
1. **Fork the repository** — Click the ["Fork" button](https://github.com/smarts-uz/appsmith-custom-table/fork) on GitHub
|
|
593
|
+
2. **Clone your fork**
|
|
594
|
+
```bash
|
|
595
|
+
git clone https://github.com/YOUR_USERNAME/appsmith-custom-table.git
|
|
596
|
+
cd appsmith-custom-table
|
|
597
|
+
```
|
|
598
|
+
3. **Make it your own** — Add features, fix bugs, customize as needed
|
|
599
|
+
4. **Publish your fork** — You can publish to npm under your own package name
|
|
600
|
+
|
|
601
|
+
### Contributing Back (Critical Fixes Only)
|
|
602
|
+
|
|
603
|
+
For critical bug fixes that benefit everyone:
|
|
604
|
+
|
|
605
|
+
1. Create a feature branch from your fork
|
|
606
|
+
2. Make minimal, focused changes
|
|
607
|
+
3. Run checks: `npm run lint && npm run build`
|
|
608
|
+
4. Submit a PR with clear description
|
|
609
|
+
|
|
610
|
+
> **Note**: Response times may be slow and PRs may not be reviewed promptly.
|
|
611
|
+
|
|
612
|
+
### Attribution
|
|
613
|
+
|
|
614
|
+
If you fork and extend this project, please:
|
|
615
|
+
- Keep the MIT license
|
|
616
|
+
- Credit the original `tablecn` project for inspiration
|
|
617
|
+
- Link back to this repository
|
|
171
618
|
|
|
172
619
|
## License
|
|
173
620
|
|
|
@@ -175,5 +622,7 @@ MIT © Ramz001
|
|
|
175
622
|
|
|
176
623
|
## Acknowledgements
|
|
177
624
|
|
|
178
|
-
|
|
625
|
+
- Thanks to the Appsmith community for the platform that inspired this widget
|
|
626
|
+
- Thanks to the `tablecn` project for foundational inspiration
|
|
627
|
+
- This project was created as a job task at [Smarts](https://github.com/smarts-uz) to demonstrate Appsmith custom widget capabilities
|
|
179
628
|
|
package/dist/app.js
CHANGED
|
@@ -40758,7 +40758,7 @@ function Uge(e) {
|
|
|
40758
40758
|
m * l >= c && x(!1);
|
|
40759
40759
|
}, [m, l, c]), he.useEffect(() => {
|
|
40760
40760
|
w?.length > 0 && p((R) => {
|
|
40761
|
-
R?.data
|
|
40761
|
+
Array.isArray(R?.data) && R.data !== w && b(R.data || []);
|
|
40762
40762
|
});
|
|
40763
40763
|
}, [w]), y.success ? /* @__PURE__ */ L1(
|
|
40764
40764
|
"main",
|
package/dist/app.umd.cjs
CHANGED
|
@@ -64,4 +64,4 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
64
64
|
.block-interactivity-`.concat(e,` {pointer-events: none;}
|
|
65
65
|
.allow-interactivity-`).concat(e,` {pointer-events: all;}
|
|
66
66
|
`)},CU=0,ei=[];function zU(e){var t=f.useRef([]),o=f.useRef([0,0]),a=f.useRef(),n=f.useState(CU++)[0],i=f.useState(_P)[0],c=f.useRef(e);f.useEffect(function(){c.current=e},[e]),f.useEffect(function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(n));var _=YE([e.lockRef.current],(e.shards||[]).map(wP),!0).filter(Boolean);return _.forEach(function(m){return m.classList.add("allow-interactivity-".concat(n))}),function(){document.body.classList.remove("block-interactivity-".concat(n)),_.forEach(function(m){return m.classList.remove("allow-interactivity-".concat(n))})}}},[e.inert,e.lockRef.current,e.shards]);var d=f.useCallback(function(_,m){if("touches"in _&&_.touches.length===2||_.type==="wheel"&&_.ctrlKey)return!c.current.allowPinchZoom;var g=ab(_),w=o.current,$="deltaX"in _?_.deltaX:w[0]-g[0],b="deltaY"in _?_.deltaY:w[1]-g[1],N,P=_.target,C=Math.abs($)>Math.abs(b)?"h":"v";if("touches"in _&&C==="h"&&P.type==="range")return!1;var I=gP(C,P);if(!I)return!0;if(I?N=C:(N=C==="v"?"h":"v",I=gP(C,P)),!I)return!1;if(!a.current&&"changedTouches"in _&&($||b)&&(a.current=N),!N)return!0;var T=a.current||N;return IU(T,m,_,T==="h"?$:b)},[]),l=f.useCallback(function(_){var m=_;if(!(!ei.length||ei[ei.length-1]!==i)){var g="deltaY"in m?$P(m):ab(m),w=t.current.filter(function(N){return N.name===m.type&&(N.target===m.target||m.target===N.shadowParent)&&LU(N.delta,g)})[0];if(w&&w.should){m.cancelable&&m.preventDefault();return}if(!w){var $=(c.current.shards||[]).map(wP).filter(Boolean).filter(function(N){return N.contains(m.target)}),b=$.length>0?d(m,$[0]):!c.current.noIsolation;b&&m.cancelable&&m.preventDefault()}}},[]),s=f.useCallback(function(_,m,g,w){var $={name:_,delta:m,target:g,should:w,shadowParent:AU(g)};t.current.push($),setTimeout(function(){t.current=t.current.filter(function(b){return b!==$})},1)},[]),u=f.useCallback(function(_){o.current=ab(_),a.current=void 0},[]),h=f.useCallback(function(_){s(_.type,$P(_),_.target,d(_,e.lockRef.current))},[]),k=f.useCallback(function(_){s(_.type,ab(_),_.target,d(_,e.lockRef.current))},[]);f.useEffect(function(){return ei.push(i),e.setCallbacks({onScrollCapture:h,onWheelCapture:h,onTouchMoveCapture:k}),document.addEventListener("wheel",l,Q1),document.addEventListener("touchmove",l,Q1),document.addEventListener("touchstart",u,Q1),function(){ei=ei.filter(function(_){return _!==i}),document.removeEventListener("wheel",l,Q1),document.removeEventListener("touchmove",l,Q1),document.removeEventListener("touchstart",u,Q1)}},[]);var p=e.removeScrollBar,y=e.inert;return f.createElement(f.Fragment,null,y?f.createElement(i,{styles:SU(n)}):null,p?f.createElement(vU,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function AU(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}const jU=cU(kP,zU);var QN=f.forwardRef(function(e,t){return f.createElement(nb,Be({},e,{ref:t,sideCar:jU}))});QN.classNames=nb.classNames;var eI=["Enter"," "],PU=["ArrowDown","PageUp","Home"],bP=["ArrowUp","PageDown","End"],qU=[...PU,...bP],DU={ltr:[...eI,"ArrowRight"],rtl:[...eI,"ArrowLeft"]},OU={ltr:["ArrowLeft"],rtl:["ArrowRight"]},Pi="Menu",[qi,HU,VU]=lj(Pi),[P1,xP]=Z1(Pi,[VU,Xw,iP]),ib=Xw(),NP=iP(),[RU,q1]=P1(Pi),[TU,Di]=P1(Pi),IP=e=>{const{__scopeMenu:t,open:o=!1,children:a,dir:n,onOpenChange:i,modal:c=!0}=e,d=ib(t),[l,s]=f.useState(null),u=f.useRef(!1),h=et(i),k=uj(n);return f.useEffect(()=>{const p=()=>{u.current=!0,document.addEventListener("pointerdown",y,{capture:!0,once:!0}),document.addEventListener("pointermove",y,{capture:!0,once:!0})},y=()=>u.current=!1;return document.addEventListener("keydown",p,{capture:!0}),()=>{document.removeEventListener("keydown",p,{capture:!0}),document.removeEventListener("pointerdown",y,{capture:!0}),document.removeEventListener("pointermove",y,{capture:!0})}},[]),M.jsx(tP,{...d,children:M.jsx(RU,{scope:t,open:o,onOpenChange:h,content:l,onContentChange:s,children:M.jsx(TU,{scope:t,onClose:f.useCallback(()=>h(!1),[h]),isUsingKeyboardRef:u,dir:k,modal:c,children:a})})})};IP.displayName=Pi;var FU="MenuAnchor",tI=f.forwardRef((e,t)=>{const{__scopeMenu:o,...a}=e,n=ib(o);return M.jsx(UN,{...n,...a,ref:t})});tI.displayName=FU;var nI="MenuPortal",[EU,LP]=P1(nI,{forceMount:void 0}),SP=e=>{const{__scopeMenu:t,forceMount:o,children:a,container:n}=e,i=q1(nI,t);return M.jsx(EU,{scope:t,forceMount:o,children:M.jsx(j1,{present:o||i.open,children:M.jsx(BN,{asChild:!0,container:n,children:a})})})};SP.displayName=nI;var be="MenuContent",[UU,oI]=P1(be),CP=f.forwardRef((e,t)=>{const o=LP(be,e.__scopeMenu),{forceMount:a=o.forceMount,...n}=e,i=q1(be,e.__scopeMenu),c=Di(be,e.__scopeMenu);return M.jsx(qi.Provider,{scope:e.__scopeMenu,children:M.jsx(j1,{present:a||i.open,children:M.jsx(qi.Slot,{scope:e.__scopeMenu,children:c.modal?M.jsx(BU,{...n,ref:t}):M.jsx(ZU,{...n,ref:t})})})})}),BU=f.forwardRef((e,t)=>{const o=q1(be,e.__scopeMenu),a=f.useRef(null),n=ue(t,a);return f.useEffect(()=>{const i=a.current;if(i)return uP(i)},[]),M.jsx(aI,{...e,ref:n,trapFocus:o.open,disableOutsidePointerEvents:o.open,disableOutsideScroll:!0,onFocusOutside:U(e.onFocusOutside,i=>i.preventDefault(),{checkForDefaultPrevented:!1}),onDismiss:()=>o.onOpenChange(!1)})}),ZU=f.forwardRef((e,t)=>{const o=q1(be,e.__scopeMenu);return M.jsx(aI,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,disableOutsideScroll:!1,onDismiss:()=>o.onOpenChange(!1)})}),GU=Si("MenuContent.ScrollLock"),aI=f.forwardRef((e,t)=>{const{__scopeMenu:o,loop:a=!1,trapFocus:n,onOpenAutoFocus:i,onCloseAutoFocus:c,disableOutsidePointerEvents:d,onEntryFocus:l,onEscapeKeyDown:s,onPointerDownOutside:u,onFocusOutside:h,onInteractOutside:k,onDismiss:p,disableOutsideScroll:y,..._}=e,m=q1(be,o),g=Di(be,o),w=ib(o),$=NP(o),b=HU(o),[N,P]=f.useState(null),C=f.useRef(null),I=ue(t,C,m.onContentChange),T=f.useRef(0),D=f.useRef(""),Z=f.useRef(0),X=f.useRef(null),J=f.useRef("right"),K=f.useRef(0),oe=y?QN:f.Fragment,B=y?{as:GU,allowPinchZoom:!0}:void 0,Y=q=>{const re=D.current+q,$e=b().filter(G=>!G.disabled),Ae=document.activeElement,ie=$e.find(G=>G.ref.current===Ae)?.textValue,de=$e.map(G=>G.textValue),ot=iB(de,re,ie),Ze=$e.find(G=>G.textValue===ot)?.ref.current;(function G(kt){D.current=kt,window.clearTimeout(T.current),kt!==""&&(T.current=window.setTimeout(()=>G(""),1e3))})(re),Ze&&setTimeout(()=>Ze.focus())};f.useEffect(()=>()=>window.clearTimeout(T.current),[]),_j();const S=f.useCallback(q=>J.current===X.current?.side&&cB(q,X.current?.area),[]);return M.jsx(UU,{scope:o,searchRef:D,onItemEnter:f.useCallback(q=>{S(q)&&q.preventDefault()},[S]),onItemLeave:f.useCallback(q=>{S(q)||(C.current?.focus(),P(null))},[S]),onTriggerLeave:f.useCallback(q=>{S(q)&&q.preventDefault()},[S]),pointerGraceTimerRef:Z,onPointerGraceIntentChange:f.useCallback(q=>{X.current=q},[]),children:M.jsx(oe,{...B,children:M.jsx(CN,{asChild:!0,trapped:n,onMountAutoFocus:U(i,q=>{q.preventDefault(),C.current?.focus({preventScroll:!0})}),onUnmountAutoFocus:c,children:M.jsx(NN,{asChild:!0,disableOutsidePointerEvents:d,onEscapeKeyDown:s,onPointerDownOutside:u,onFocusOutside:h,onInteractOutside:k,onDismiss:p,children:M.jsx(GE,{asChild:!0,...$,dir:g.dir,orientation:"vertical",loop:a,currentTabStopId:N,onCurrentTabStopIdChange:P,onEntryFocus:U(l,q=>{g.isUsingKeyboardRef.current||q.preventDefault()}),preventScrollOnEntryFocus:!0,children:M.jsx(nP,{role:"menu","aria-orientation":"vertical","data-state":GP(m.open),"data-radix-menu-content":"",dir:g.dir,...w,..._,ref:I,style:{outline:"none",..._.style},onKeyDown:U(_.onKeyDown,q=>{const $e=q.target.closest("[data-radix-menu-content]")===q.currentTarget,Ae=q.ctrlKey||q.altKey||q.metaKey,ie=q.key.length===1;$e&&(q.key==="Tab"&&q.preventDefault(),!Ae&&ie&&Y(q.key));const de=C.current;if(q.target!==de||!qU.includes(q.key))return;q.preventDefault();const Ze=b().filter(G=>!G.disabled).map(G=>G.ref.current);bP.includes(q.key)&&Ze.reverse(),oB(Ze)}),onBlur:U(e.onBlur,q=>{q.currentTarget.contains(q.target)||(window.clearTimeout(T.current),D.current="")}),onPointerMove:U(e.onPointerMove,Hi(q=>{const re=q.target,$e=K.current!==q.clientX;if(q.currentTarget.contains(re)&&$e){const Ae=q.clientX>K.current?"right":"left";J.current=Ae,K.current=q.clientX}}))})})})})})})});CP.displayName=be;var WU="MenuGroup",iI=f.forwardRef((e,t)=>{const{__scopeMenu:o,...a}=e;return M.jsx(se.div,{role:"group",...a,ref:t})});iI.displayName=WU;var KU="MenuLabel",zP=f.forwardRef((e,t)=>{const{__scopeMenu:o,...a}=e;return M.jsx(se.div,{...a,ref:t})});zP.displayName=KU;var rb="MenuItem",AP="menu.itemSelect",cb=f.forwardRef((e,t)=>{const{disabled:o=!1,onSelect:a,...n}=e,i=f.useRef(null),c=Di(rb,e.__scopeMenu),d=oI(rb,e.__scopeMenu),l=ue(t,i),s=f.useRef(!1),u=()=>{const h=i.current;if(!o&&h){const k=new CustomEvent(AP,{bubbles:!0,cancelable:!0});h.addEventListener(AP,p=>a?.(p),{once:!0}),sj(h,k),k.defaultPrevented?s.current=!1:c.onClose()}};return M.jsx(jP,{...n,ref:l,disabled:o,onClick:U(e.onClick,u),onPointerDown:h=>{e.onPointerDown?.(h),s.current=!0},onPointerUp:U(e.onPointerUp,h=>{s.current||h.currentTarget?.click()}),onKeyDown:U(e.onKeyDown,h=>{const k=d.searchRef.current!=="";o||k&&h.key===" "||eI.includes(h.key)&&(h.currentTarget.click(),h.preventDefault())})})});cb.displayName=rb;var jP=f.forwardRef((e,t)=>{const{__scopeMenu:o,disabled:a=!1,textValue:n,...i}=e,c=oI(rb,o),d=NP(o),l=f.useRef(null),s=ue(t,l),[u,h]=f.useState(!1),[k,p]=f.useState("");return f.useEffect(()=>{const y=l.current;y&&p((y.textContent??"").trim())},[i.children]),M.jsx(qi.ItemSlot,{scope:o,disabled:a,textValue:n??k,children:M.jsx(WE,{asChild:!0,...d,focusable:!a,children:M.jsx(se.div,{role:"menuitem","data-highlighted":u?"":void 0,"aria-disabled":a||void 0,"data-disabled":a?"":void 0,...i,ref:s,onPointerMove:U(e.onPointerMove,Hi(y=>{a?c.onItemLeave(y):(c.onItemEnter(y),y.defaultPrevented||y.currentTarget.focus({preventScroll:!0}))})),onPointerLeave:U(e.onPointerLeave,Hi(y=>c.onItemLeave(y))),onFocus:U(e.onFocus,()=>h(!0)),onBlur:U(e.onBlur,()=>h(!1))})})})}),XU="MenuCheckboxItem",PP=f.forwardRef((e,t)=>{const{checked:o=!1,onCheckedChange:a,...n}=e;return M.jsx(VP,{scope:e.__scopeMenu,checked:o,children:M.jsx(cb,{role:"menuitemcheckbox","aria-checked":db(o)?"mixed":o,...n,ref:t,"data-state":cI(o),onSelect:U(n.onSelect,()=>a?.(db(o)?!0:!o),{checkForDefaultPrevented:!1})})})});PP.displayName=XU;var qP="MenuRadioGroup",[JU,YU]=P1(qP,{value:void 0,onValueChange:()=>{}}),DP=f.forwardRef((e,t)=>{const{value:o,onValueChange:a,...n}=e,i=et(a);return M.jsx(JU,{scope:e.__scopeMenu,value:o,onValueChange:i,children:M.jsx(iI,{...n,ref:t})})});DP.displayName=qP;var OP="MenuRadioItem",HP=f.forwardRef((e,t)=>{const{value:o,...a}=e,n=YU(OP,e.__scopeMenu),i=o===n.value;return M.jsx(VP,{scope:e.__scopeMenu,checked:i,children:M.jsx(cb,{role:"menuitemradio","aria-checked":i,...a,ref:t,"data-state":cI(i),onSelect:U(a.onSelect,()=>n.onValueChange?.(o),{checkForDefaultPrevented:!1})})})});HP.displayName=OP;var rI="MenuItemIndicator",[VP,QU]=P1(rI,{checked:!1}),RP=f.forwardRef((e,t)=>{const{__scopeMenu:o,forceMount:a,...n}=e,i=QU(rI,o);return M.jsx(j1,{present:a||db(i.checked)||i.checked===!0,children:M.jsx(se.span,{...n,ref:t,"data-state":cI(i.checked)})})});RP.displayName=rI;var eB="MenuSeparator",TP=f.forwardRef((e,t)=>{const{__scopeMenu:o,...a}=e;return M.jsx(se.div,{role:"separator","aria-orientation":"horizontal",...a,ref:t})});TP.displayName=eB;var tB="MenuArrow",FP=f.forwardRef((e,t)=>{const{__scopeMenu:o,...a}=e,n=ib(o);return M.jsx(oP,{...n,...a,ref:t})});FP.displayName=tB;var nB="MenuSub",[qme,EP]=P1(nB),Oi="MenuSubTrigger",UP=f.forwardRef((e,t)=>{const o=q1(Oi,e.__scopeMenu),a=Di(Oi,e.__scopeMenu),n=EP(Oi,e.__scopeMenu),i=oI(Oi,e.__scopeMenu),c=f.useRef(null),{pointerGraceTimerRef:d,onPointerGraceIntentChange:l}=i,s={__scopeMenu:e.__scopeMenu},u=f.useCallback(()=>{c.current&&window.clearTimeout(c.current),c.current=null},[]);return f.useEffect(()=>u,[u]),f.useEffect(()=>{const h=d.current;return()=>{window.clearTimeout(h),l(null)}},[d,l]),M.jsx(tI,{asChild:!0,...s,children:M.jsx(jP,{id:n.triggerId,"aria-haspopup":"menu","aria-expanded":o.open,"aria-controls":n.contentId,"data-state":GP(o.open),...e,ref:Li(t,n.onTriggerChange),onClick:h=>{e.onClick?.(h),!(e.disabled||h.defaultPrevented)&&(h.currentTarget.focus(),o.open||o.onOpenChange(!0))},onPointerMove:U(e.onPointerMove,Hi(h=>{i.onItemEnter(h),!h.defaultPrevented&&!e.disabled&&!o.open&&!c.current&&(i.onPointerGraceIntentChange(null),c.current=window.setTimeout(()=>{o.onOpenChange(!0),u()},100))})),onPointerLeave:U(e.onPointerLeave,Hi(h=>{u();const k=o.content?.getBoundingClientRect();if(k){const p=o.content?.dataset.side,y=p==="right",_=y?-5:5,m=k[y?"left":"right"],g=k[y?"right":"left"];i.onPointerGraceIntentChange({area:[{x:h.clientX+_,y:h.clientY},{x:m,y:k.top},{x:g,y:k.top},{x:g,y:k.bottom},{x:m,y:k.bottom}],side:p}),window.clearTimeout(d.current),d.current=window.setTimeout(()=>i.onPointerGraceIntentChange(null),300)}else{if(i.onTriggerLeave(h),h.defaultPrevented)return;i.onPointerGraceIntentChange(null)}})),onKeyDown:U(e.onKeyDown,h=>{const k=i.searchRef.current!=="";e.disabled||k&&h.key===" "||DU[a.dir].includes(h.key)&&(o.onOpenChange(!0),o.content?.focus(),h.preventDefault())})})})});UP.displayName=Oi;var BP="MenuSubContent",ZP=f.forwardRef((e,t)=>{const o=LP(be,e.__scopeMenu),{forceMount:a=o.forceMount,...n}=e,i=q1(be,e.__scopeMenu),c=Di(be,e.__scopeMenu),d=EP(BP,e.__scopeMenu),l=f.useRef(null),s=ue(t,l);return M.jsx(qi.Provider,{scope:e.__scopeMenu,children:M.jsx(j1,{present:a||i.open,children:M.jsx(qi.Slot,{scope:e.__scopeMenu,children:M.jsx(aI,{id:d.contentId,"aria-labelledby":d.triggerId,...n,ref:s,align:"start",side:c.dir==="rtl"?"left":"right",disableOutsidePointerEvents:!1,disableOutsideScroll:!1,trapFocus:!1,onOpenAutoFocus:u=>{c.isUsingKeyboardRef.current&&l.current?.focus(),u.preventDefault()},onCloseAutoFocus:u=>u.preventDefault(),onFocusOutside:U(e.onFocusOutside,u=>{u.target!==d.trigger&&i.onOpenChange(!1)}),onEscapeKeyDown:U(e.onEscapeKeyDown,u=>{c.onClose(),u.preventDefault()}),onKeyDown:U(e.onKeyDown,u=>{const h=u.currentTarget.contains(u.target),k=OU[c.dir].includes(u.key);h&&k&&(i.onOpenChange(!1),d.trigger?.focus(),u.preventDefault())})})})})})});ZP.displayName=BP;function GP(e){return e?"open":"closed"}function db(e){return e==="indeterminate"}function cI(e){return db(e)?"indeterminate":e?"checked":"unchecked"}function oB(e){const t=document.activeElement;for(const o of e)if(o===t||(o.focus(),document.activeElement!==t))return}function aB(e,t){return e.map((o,a)=>e[(t+a)%e.length])}function iB(e,t,o){const n=t.length>1&&Array.from(t).every(s=>s===t[0])?t[0]:t,i=o?e.indexOf(o):-1;let c=aB(e,Math.max(i,0));n.length===1&&(c=c.filter(s=>s!==o));const l=c.find(s=>s.toLowerCase().startsWith(n.toLowerCase()));return l!==o?l:void 0}function rB(e,t){const{x:o,y:a}=e;let n=!1;for(let i=0,c=t.length-1;i<t.length;c=i++){const d=t[i],l=t[c],s=d.x,u=d.y,h=l.x,k=l.y;u>a!=k>a&&o<(h-s)*(a-u)/(k-u)+s&&(n=!n)}return n}function cB(e,t){if(!t)return!1;const o={x:e.clientX,y:e.clientY};return rB(o,t)}function Hi(e){return t=>t.pointerType==="mouse"?e(t):void 0}var dB=IP,sB=tI,lB=SP,uB=CP,hB=iI,pB=zP,yB=cb,kB=PP,_B=DP,fB=HP,mB=RP,gB=TP,vB=FP,MB=UP,$B=ZP,sb="DropdownMenu",[wB]=Z1(sb,[xP]),ye=xP(),[bB,WP]=wB(sb),KP=e=>{const{__scopeDropdownMenu:t,children:o,dir:a,open:n,defaultOpen:i,onOpenChange:c,modal:d=!0}=e,l=ye(t),s=f.useRef(null),[u,h]=bN({prop:n,defaultProp:i??!1,onChange:c,caller:sb});return M.jsx(bB,{scope:t,triggerId:Vw(),triggerRef:s,contentId:Vw(),open:u,onOpenChange:h,onOpenToggle:f.useCallback(()=>h(k=>!k),[h]),modal:d,children:M.jsx(dB,{...l,open:u,onOpenChange:h,dir:a,modal:d,children:o})})};KP.displayName=sb;var XP="DropdownMenuTrigger",JP=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,disabled:a=!1,...n}=e,i=WP(XP,o),c=ye(o);return M.jsx(sB,{asChild:!0,...c,children:M.jsx(se.button,{type:"button",id:i.triggerId,"aria-haspopup":"menu","aria-expanded":i.open,"aria-controls":i.open?i.contentId:void 0,"data-state":i.open?"open":"closed","data-disabled":a?"":void 0,disabled:a,...n,ref:Li(t,i.triggerRef),onPointerDown:U(e.onPointerDown,d=>{!a&&d.button===0&&d.ctrlKey===!1&&(i.onOpenToggle(),i.open||d.preventDefault())}),onKeyDown:U(e.onKeyDown,d=>{a||(["Enter"," "].includes(d.key)&&i.onOpenToggle(),d.key==="ArrowDown"&&i.onOpenChange(!0),["Enter"," ","ArrowDown"].includes(d.key)&&d.preventDefault())})})})});JP.displayName=XP;var xB="DropdownMenuPortal",YP=e=>{const{__scopeDropdownMenu:t,...o}=e,a=ye(t);return M.jsx(lB,{...a,...o})};YP.displayName=xB;var QP="DropdownMenuContent",eq=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=WP(QP,o),i=ye(o),c=f.useRef(!1);return M.jsx(uB,{id:n.contentId,"aria-labelledby":n.triggerId,...i,...a,ref:t,onCloseAutoFocus:U(e.onCloseAutoFocus,d=>{c.current||n.triggerRef.current?.focus(),c.current=!1,d.preventDefault()}),onInteractOutside:U(e.onInteractOutside,d=>{const l=d.detail.originalEvent,s=l.button===0&&l.ctrlKey===!0,u=l.button===2||s;(!n.modal||u)&&(c.current=!0)}),style:{...e.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});eq.displayName=QP;var NB="DropdownMenuGroup",IB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(hB,{...n,...a,ref:t})});IB.displayName=NB;var LB="DropdownMenuLabel",SB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(pB,{...n,...a,ref:t})});SB.displayName=LB;var CB="DropdownMenuItem",tq=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(yB,{...n,...a,ref:t})});tq.displayName=CB;var zB="DropdownMenuCheckboxItem",AB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(kB,{...n,...a,ref:t})});AB.displayName=zB;var jB="DropdownMenuRadioGroup",PB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(_B,{...n,...a,ref:t})});PB.displayName=jB;var qB="DropdownMenuRadioItem",DB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(fB,{...n,...a,ref:t})});DB.displayName=qB;var OB="DropdownMenuItemIndicator",HB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(mB,{...n,...a,ref:t})});HB.displayName=OB;var VB="DropdownMenuSeparator",RB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(gB,{...n,...a,ref:t})});RB.displayName=VB;var TB="DropdownMenuArrow",FB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(vB,{...n,...a,ref:t})});FB.displayName=TB;var EB="DropdownMenuSubTrigger",UB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx(MB,{...n,...a,ref:t})});UB.displayName=EB;var BB="DropdownMenuSubContent",ZB=f.forwardRef((e,t)=>{const{__scopeDropdownMenu:o,...a}=e,n=ye(o);return M.jsx($B,{...n,...a,ref:t,style:{...e.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});ZB.displayName=BB;var GB=KP,WB=JP,KB=YP,XB=eq,JB=tq;function YB({...e}){return M.jsx(GB,{"data-slot":"dropdown-menu",...e})}function QB({...e}){return M.jsx(WB,{"data-slot":"dropdown-menu-trigger",...e})}function eZ({className:e,sideOffset:t=4,...o}){return M.jsx(KB,{children:M.jsx(XB,{"data-slot":"dropdown-menu-content",sideOffset:t,className:ae("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",e),...o})})}function tZ({className:e,inset:t,variant:o="default",...a}){return M.jsx(JB,{"data-slot":"dropdown-menu-item","data-inset":t,"data-variant":o,className:ae("focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",e),...a})}function nZ({row:e,type:t,actionColumn:o,triggerEvent:a,locale:n,updateModel:i}){const c=(s,u)=>{u.stopPropagation(),a&&a(s,{row:e.original}),i&&i({triggeredRow:e.original})},d=o?.actions?.length===1,l=s=>{const u=s&&Ow[s]?Ow[s]:Ni;return M.jsx(u,{className:"w-5 h-5 text-inherit"})};if(e.original?.__empty)return null;if(d){const s=o?.actions[0];return M.jsx(dj,{variant:t||"default",size:"icon",className:ae("w-full min-w-8 h-full p-2 flex items-center gap-2",s?.className),onClick:u=>c(s.onClick,u),children:l(s.icon)})}return M.jsxs(YB,{children:[M.jsx(QB,{children:M.jsx(dj,{asChild:!0,size:"icon",variant:t||"default",className:"w-full h-full p-2 min-w-8 mx-auto",children:l(o?.icon||"MoreHorizontal")})}),M.jsx(eZ,{align:"end",className:"w-64",children:o?.actions?.map((s,u)=>M.jsxs(tZ,{className:ae("flex items-center gap-2 text-base font-semibold",s?.className),onClick:h=>c(s.onClick,h),children:[l(s.icon),s.title[n]]},u))})]})}var lb="Popover",[nq]=Z1(lb,[Xw]),Vi=Xw(),[oZ,yt]=nq(lb),oq=e=>{const{__scopePopover:t,children:o,open:a,defaultOpen:n,onOpenChange:i,modal:c=!1}=e,d=Vi(t),l=f.useRef(null),[s,u]=f.useState(!1),[h,k]=bN({prop:a,defaultProp:n??!1,onChange:i,caller:lb});return M.jsx(tP,{...d,children:M.jsx(oZ,{scope:t,contentId:Vw(),triggerRef:l,open:h,onOpenChange:k,onOpenToggle:f.useCallback(()=>k(p=>!p),[k]),hasCustomAnchor:s,onCustomAnchorAdd:f.useCallback(()=>u(!0),[]),onCustomAnchorRemove:f.useCallback(()=>u(!1),[]),modal:c,children:o})})};oq.displayName=lb;var aq="PopoverAnchor",aZ=f.forwardRef((e,t)=>{const{__scopePopover:o,...a}=e,n=yt(aq,o),i=Vi(o),{onCustomAnchorAdd:c,onCustomAnchorRemove:d}=n;return f.useEffect(()=>(c(),()=>d()),[c,d]),M.jsx(UN,{...i,...a,ref:t})});aZ.displayName=aq;var iq="PopoverTrigger",rq=f.forwardRef((e,t)=>{const{__scopePopover:o,...a}=e,n=yt(iq,o),i=Vi(o),c=ue(t,n.triggerRef),d=M.jsx(se.button,{type:"button","aria-haspopup":"dialog","aria-expanded":n.open,"aria-controls":n.contentId,"data-state":uq(n.open),...a,ref:c,onClick:U(e.onClick,n.onOpenToggle)});return n.hasCustomAnchor?d:M.jsx(UN,{asChild:!0,...i,children:d})});rq.displayName=iq;var dI="PopoverPortal",[iZ,rZ]=nq(dI,{forceMount:void 0}),cq=e=>{const{__scopePopover:t,forceMount:o,children:a,container:n}=e,i=yt(dI,t);return M.jsx(iZ,{scope:t,forceMount:o,children:M.jsx(j1,{present:o||i.open,children:M.jsx(BN,{asChild:!0,container:n,children:a})})})};cq.displayName=dI;var ti="PopoverContent",dq=f.forwardRef((e,t)=>{const o=rZ(ti,e.__scopePopover),{forceMount:a=o.forceMount,...n}=e,i=yt(ti,e.__scopePopover);return M.jsx(j1,{present:a||i.open,children:i.modal?M.jsx(dZ,{...n,ref:t}):M.jsx(sZ,{...n,ref:t})})});dq.displayName=ti;var cZ=Si("PopoverContent.RemoveScroll"),dZ=f.forwardRef((e,t)=>{const o=yt(ti,e.__scopePopover),a=f.useRef(null),n=ue(t,a),i=f.useRef(!1);return f.useEffect(()=>{const c=a.current;if(c)return uP(c)},[]),M.jsx(QN,{as:cZ,allowPinchZoom:!0,children:M.jsx(sq,{...e,ref:n,trapFocus:o.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:U(e.onCloseAutoFocus,c=>{c.preventDefault(),i.current||o.triggerRef.current?.focus()}),onPointerDownOutside:U(e.onPointerDownOutside,c=>{const d=c.detail.originalEvent,l=d.button===0&&d.ctrlKey===!0,s=d.button===2||l;i.current=s},{checkForDefaultPrevented:!1}),onFocusOutside:U(e.onFocusOutside,c=>c.preventDefault(),{checkForDefaultPrevented:!1})})})}),sZ=f.forwardRef((e,t)=>{const o=yt(ti,e.__scopePopover),a=f.useRef(!1),n=f.useRef(!1);return M.jsx(sq,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:i=>{e.onCloseAutoFocus?.(i),i.defaultPrevented||(a.current||o.triggerRef.current?.focus(),i.preventDefault()),a.current=!1,n.current=!1},onInteractOutside:i=>{e.onInteractOutside?.(i),i.defaultPrevented||(a.current=!0,i.detail.originalEvent.type==="pointerdown"&&(n.current=!0));const c=i.target;o.triggerRef.current?.contains(c)&&i.preventDefault(),i.detail.originalEvent.type==="focusin"&&n.current&&i.preventDefault()}})}),sq=f.forwardRef((e,t)=>{const{__scopePopover:o,trapFocus:a,onOpenAutoFocus:n,onCloseAutoFocus:i,disableOutsidePointerEvents:c,onEscapeKeyDown:d,onPointerDownOutside:l,onFocusOutside:s,onInteractOutside:u,...h}=e,k=yt(ti,o),p=Vi(o);return _j(),M.jsx(CN,{asChild:!0,loop:!0,trapped:a,onMountAutoFocus:n,onUnmountAutoFocus:i,children:M.jsx(NN,{asChild:!0,disableOutsidePointerEvents:c,onInteractOutside:u,onEscapeKeyDown:d,onPointerDownOutside:l,onFocusOutside:s,onDismiss:()=>k.onOpenChange(!1),children:M.jsx(nP,{"data-state":uq(k.open),role:"dialog",id:k.contentId,...p,...h,ref:t,style:{...h.style,"--radix-popover-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-popover-content-available-width":"var(--radix-popper-available-width)","--radix-popover-content-available-height":"var(--radix-popper-available-height)","--radix-popover-trigger-width":"var(--radix-popper-anchor-width)","--radix-popover-trigger-height":"var(--radix-popper-anchor-height)"}})})})}),lq="PopoverClose",lZ=f.forwardRef((e,t)=>{const{__scopePopover:o,...a}=e,n=yt(lq,o);return M.jsx(se.button,{type:"button",...a,ref:t,onClick:U(e.onClick,()=>n.onOpenChange(!1))})});lZ.displayName=lq;var uZ="PopoverArrow",hZ=f.forwardRef((e,t)=>{const{__scopePopover:o,...a}=e,n=Vi(o);return M.jsx(oP,{...n,...a,ref:t})});hZ.displayName=uZ;function uq(e){return e?"open":"closed"}var pZ=oq,yZ=rq,kZ=cq,_Z=dq;function fZ({...e}){return M.jsx(pZ,{"data-slot":"popover",...e})}function mZ({...e}){return M.jsx(yZ,{"data-slot":"popover-trigger",...e})}function gZ({className:e,align:t="center",sideOffset:o=4,...a}){return M.jsx(kZ,{children:M.jsx(_Z,{"data-slot":"popover-content",align:t,sideOffset:o,className:ae("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",e),...a})})}function vZ(e){const t=new Date(e);if(isNaN(t.getTime()))return String(e);const o=String(t.getDate()).padStart(2,"0"),a=String(t.getMonth()+1).padStart(2,"0"),n=t.getFullYear();return`${o}-${a}-${n}`}function MZ(e){const t=new Date(e);if(isNaN(t.getTime()))return String(e);const o=String(t.getDate()).padStart(2,"0"),a=String(t.getMonth()+1).padStart(2,"0"),n=t.getFullYear(),i=String(t.getHours()).padStart(2,"0"),c=String(t.getMinutes()).padStart(2,"0");return`${o}-${a}-${n} ${i}:${c}`}function $Z(e){let t=e.replace(/\D/g,"");return t.startsWith("+998")&&(t=t.slice(4)),t.slice(0,9)}function wZ(e){const t=$Z(e);return t.length===0?"":[t.slice(0,2),t.slice(2,5),t.slice(5,7),t.slice(7,9)].filter(Boolean).join(" ")}const bZ=({value:e,type:t,triggerEvent:o,className:a})=>{const n=typeof e=="object"?JSON.stringify(e):String(e),i=ee.useRef(null),[c,d]=ee.useState(!1);if(ee.useEffect(()=>{const s=i.current;s&&d(s.scrollWidth>s.clientWidth)},[n]),e==null||typeof e=="number"&&isNaN(+e))return M.jsx(M.Fragment,{});const l=M.jsx("div",{ref:i,className:ae("truncate text-center max-w-[160px] md:max-w-[256px] lg:max-w-[320px] lg:text-start",a),children:xZ(n,t,o)});return c&&t!=="url"?M.jsxs(fZ,{children:[M.jsx(mZ,{className:"h-min max-w-40 md:max-w-64 lg:max-w-full lg:text-start",onClick:s=>s.stopPropagation(),title:n,children:l}),M.jsx(gZ,{onOpenAutoFocus:s=>s.preventDefault(),align:"center",className:"w-64 lg:w-80 break-words",children:n})]}):l},xZ=(e,t,o)=>{switch(t){case"text":return String(e);case"url":const[a,n]=String(e).split("|||");return M.jsx("div",{className:"text-primary underline cursor-pointer select-none",onClick:i=>{i.stopPropagation(),o&&o("onRedirect",{url:n})},children:a});case"phone":return wZ(String(e));case"date":return vZ(e);case"datetime":return MZ(e);case"currency":return Number(e).toLocaleString("uz-UZ");default:return String(e)}};oj.omit({rowSelectionAction:!0,tableData:!0,limit:!0,max_count:!0,styles:!0,onModelChange:!0});function NZ({schema:e,indexColumn:t,actionColumn:o,updateModel:a,locale:n,triggerEvent:i}){const c=[];t?.enable&&c.push({id:"index",header:"№",meta:{size:ft.xs},cell:({row:s})=>M.jsx("span",{className:t?.className,children:s.index+1})});const d=Object.entries(e).map(([s,u])=>{const{size:h=ft.md,title:k,className:p}=u,y=k?k[n]:s[0].toUpperCase()+s.slice(1);return{accessorKey:s,header:y,meta:{headerText:y,size:h},cell:m=>M.jsx(bZ,{value:m.getValue(),type:u.type||"text",triggerEvent:i,className:p})}}).filter(Boolean),l=[];return o?.enable&&o.actions.length>0&&l.push({id:"actions",header:"",meta:{size:ft.xs},cell:({row:s})=>M.jsx(nZ,{updateModel:a,type:o.type,triggerEvent:i,row:s,locale:n,actionColumn:o})}),[...c,...d,...l]}function IZ(e){try{return oj.parse(e),{success:!0}}catch(t){return console.error(t),t instanceof z.ZodError?{success:!1,error:t.issues.map(a=>a.message).join(`
|
|
67
|
-
`)}:{success:!1,error:t}}}function LZ({className:e,...t}){return M.jsx("div",{"data-slot":"card",className:ae("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",e),...t})}function SZ({className:e,...t}){return M.jsx("div",{"data-slot":"card-header",className:ae("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",e),...t})}function CZ({className:e,...t}){return M.jsx("div",{"data-slot":"card-content",className:ae("px-6",e),...t})}const zZ={info:{text:"text-blue-700",border:"border-blue-300",bg:"bg-blue-100/50",defaultIcon:"ℹ️"},warning:{text:"text-yellow-800",border:"border-yellow-300",bg:"bg-yellow-100/50",defaultIcon:"⚠️"},error:{text:"text-red-700",border:"border-red-400",bg:"bg-red-100/30",defaultIcon:"❌"},success:{text:"text-green-700",border:"border-green-300",bg:"bg-green-100/50",defaultIcon:"✅"}},AZ=({title:e,message:t,variant:o="info",icon:a,className:n=""})=>{const i=zZ[o];return M.jsxs(LZ,{className:`mx-auto max-w-md mt-8 w-full h-full flex flex-col justify-center border ${i.border} ${i.bg} ${n}`,children:[M.jsxs(SZ,{className:`flex items-center gap-2 font-semibold ${i.text}`,children:[a??i.defaultIcon,M.jsx("span",{children:e??o.charAt(0).toUpperCase()+o.slice(1)})]}),M.jsx(CZ,{className:`whitespace-normal break-words ${i.text}`,children:t})]})};function jZ(e){const{schema:t,rowSelectionAction:o,actionColumn:a,indexColumn:n,tableData:i,max_count:c=Ki,styles:d,limit:l=Ki,conditionalRowStyles:s,locale:u,updateModel:h=()=>{},triggerEvent:k=()=>{},onModelChange:p=()=>{}}=e,y=IZ(e),[_,m]=ee.useState(0),[g,w]=ee.useState(!0),[$,b]=ee.useState(i||[]),N=ee.useMemo(()=>{const D=$||[],Z=l-D.length;if(Z>0){const X=Object.fromEntries(Object.keys(t).map(K=>[K,void 0])),J=Array.from({length:Z},()=>({__empty:!0,...X}));return[...D,...J]}return D},[$,l,t]),P=ee.useCallback(()=>{const D=[],Z=[];return n?.enable&&n?.pin&&(n?.pin===Xe.left?D.push("index"):n?.pin===Xe.right&&Z.push("index")),a?.enable&&a?.pin&&a?.actions?.length>0&&(a?.pin===Xe.left?D.push("actions"):a?.pin===Xe.right&&Z.push("actions")),{left:D,right:Z}},[n,a]),C=NZ({schema:t,indexColumn:n,actionColumn:a,updateModel:h,triggerEvent:k,locale:u}),I=tD({data:N,columns:C,getCoreRowModel:Jq(),state:{columnPinning:P()},manualSorting:!0}),T=(D,Z)=>{if(!D||!g||!Z.isIntersecting||$?.length<_*l)return;const X=_+1;m(X),k("onLoadMore",{page:X,limit:l})};return ee.useEffect(()=>{_*l>=c&&w(!1)},[_,l,c]),ee.useEffect(()=>{$?.length>0&&p(D=>{D?.data
|
|
67
|
+
`)}:{success:!1,error:t}}}function LZ({className:e,...t}){return M.jsx("div",{"data-slot":"card",className:ae("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",e),...t})}function SZ({className:e,...t}){return M.jsx("div",{"data-slot":"card-header",className:ae("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",e),...t})}function CZ({className:e,...t}){return M.jsx("div",{"data-slot":"card-content",className:ae("px-6",e),...t})}const zZ={info:{text:"text-blue-700",border:"border-blue-300",bg:"bg-blue-100/50",defaultIcon:"ℹ️"},warning:{text:"text-yellow-800",border:"border-yellow-300",bg:"bg-yellow-100/50",defaultIcon:"⚠️"},error:{text:"text-red-700",border:"border-red-400",bg:"bg-red-100/30",defaultIcon:"❌"},success:{text:"text-green-700",border:"border-green-300",bg:"bg-green-100/50",defaultIcon:"✅"}},AZ=({title:e,message:t,variant:o="info",icon:a,className:n=""})=>{const i=zZ[o];return M.jsxs(LZ,{className:`mx-auto max-w-md mt-8 w-full h-full flex flex-col justify-center border ${i.border} ${i.bg} ${n}`,children:[M.jsxs(SZ,{className:`flex items-center gap-2 font-semibold ${i.text}`,children:[a??i.defaultIcon,M.jsx("span",{children:e??o.charAt(0).toUpperCase()+o.slice(1)})]}),M.jsx(CZ,{className:`whitespace-normal break-words ${i.text}`,children:t})]})};function jZ(e){const{schema:t,rowSelectionAction:o,actionColumn:a,indexColumn:n,tableData:i,max_count:c=Ki,styles:d,limit:l=Ki,conditionalRowStyles:s,locale:u,updateModel:h=()=>{},triggerEvent:k=()=>{},onModelChange:p=()=>{}}=e,y=IZ(e),[_,m]=ee.useState(0),[g,w]=ee.useState(!0),[$,b]=ee.useState(i||[]),N=ee.useMemo(()=>{const D=$||[],Z=l-D.length;if(Z>0){const X=Object.fromEntries(Object.keys(t).map(K=>[K,void 0])),J=Array.from({length:Z},()=>({__empty:!0,...X}));return[...D,...J]}return D},[$,l,t]),P=ee.useCallback(()=>{const D=[],Z=[];return n?.enable&&n?.pin&&(n?.pin===Xe.left?D.push("index"):n?.pin===Xe.right&&Z.push("index")),a?.enable&&a?.pin&&a?.actions?.length>0&&(a?.pin===Xe.left?D.push("actions"):a?.pin===Xe.right&&Z.push("actions")),{left:D,right:Z}},[n,a]),C=NZ({schema:t,indexColumn:n,actionColumn:a,updateModel:h,triggerEvent:k,locale:u}),I=tD({data:N,columns:C,getCoreRowModel:Jq(),state:{columnPinning:P()},manualSorting:!0}),T=(D,Z)=>{if(!D||!g||!Z.isIntersecting||$?.length<_*l)return;const X=_+1;m(X),k("onLoadMore",{page:X,limit:l})};return ee.useEffect(()=>{_*l>=c&&w(!1)},[_,l,c]),ee.useEffect(()=>{$?.length>0&&p(D=>{Array.isArray(D?.data)&&D.data!==$&&b(D.data||[])})},[$]),y.success?M.jsxs("main",{className:ae("max-h-[40rem] md:max-h-[48rem] lg:max-h-[56rem] flex flex-col gap-2 overflow-auto font-sans relative ",g&&"pb-2",d?.container),style:{...d?.variables},children:[M.jsxs(ED,{className:ae("w-full min-w-80 h-full table-auto border-collapse",d?.table),children:[M.jsx(ST,{styles:d?.head,table:I}),M.jsx(JD,{rowSelectionAction:o,updateModel:h,triggerEvent:k,styles:d?.body,table:I,conditionalRowStyles:s})]}),g&&M.jsx(vq,{triggerOnce:!1,as:"div",threshold:0,rootMargin:"200px 0px",onChange:(D,Z)=>T(D,Z),className:"h-10 text-muted-foreground relative flex justify-center items-center",children:M.jsx(Ii,{className:"animate-spin "})})]}):M.jsx(AZ,{message:typeof y.error=="string"?y.error:"Table configuration is invalid. Check the errors above.",variant:"error"})}Ge.ClientTable=jZ,Object.defineProperty(Ge,Symbol.toStringTag,{value:"Module"})}));
|