@ttoss/react-dashboard 0.1.13 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,11 +26,16 @@ import type {
26
26
 
27
27
  const templates: DashboardTemplate[] = [];
28
28
  const filters: DashboardFilter[] = [];
29
+ const selectedTemplate: DashboardTemplate | undefined = undefined;
29
30
 
30
31
  ReactDOM.render(
31
32
  <React.StrictMode>
32
33
  <ThemeProvider>
33
- <DashboardProvider filters={filters} templates={templates}>
34
+ <DashboardProvider
35
+ filters={filters}
36
+ templates={templates}
37
+ selectedTemplate={selectedTemplate}
38
+ >
34
39
  <App />
35
40
  </DashboardProvider>
36
41
  </ThemeProvider>
@@ -50,31 +55,29 @@ import type {
50
55
  import { DashboardFilterType } from '@ttoss/react-dashboard';
51
56
 
52
57
  const MyDashboard = () => {
53
- const templates: DashboardTemplate[] = [
54
- {
55
- id: 'default',
56
- name: 'Default Template',
57
- description: 'My default dashboard layout',
58
- grid: [
59
- {
60
- i: 'card-1',
61
- x: 0,
62
- y: 0,
63
- w: 4,
64
- h: 4,
65
- card: {
66
- title: 'Total Revenue',
67
- numberType: 'currency',
68
- type: 'bigNumber',
69
- sourceType: [{ source: 'api' }],
70
- data: {
71
- api: { total: 150000 },
72
- },
58
+ const selectedTemplate: DashboardTemplate = {
59
+ id: 'default',
60
+ name: 'Default Template',
61
+ description: 'My default dashboard layout',
62
+ grid: [
63
+ {
64
+ i: 'card-1',
65
+ x: 0,
66
+ y: 0,
67
+ w: 4,
68
+ h: 4,
69
+ card: {
70
+ title: 'Total Revenue',
71
+ numberType: 'currency',
72
+ type: 'bigNumber',
73
+ sourceType: [{ source: 'api' }],
74
+ data: {
75
+ api: { total: 150000 },
73
76
  },
74
77
  },
75
- ],
76
- },
77
- ];
78
+ },
79
+ ],
80
+ };
78
81
 
79
82
  const filters: DashboardFilter[] = [
80
83
  {
@@ -85,7 +88,14 @@ const MyDashboard = () => {
85
88
  },
86
89
  ];
87
90
 
88
- return <Dashboard templates={templates} filters={filters} loading={false} />;
91
+ return (
92
+ <Dashboard
93
+ selectedTemplate={selectedTemplate}
94
+ templates={[]}
95
+ filters={filters}
96
+ loading={false}
97
+ />
98
+ );
89
99
  };
90
100
  ```
91
101
 
@@ -99,6 +109,7 @@ The main dashboard component that orchestrates the entire dashboard experience.
99
109
  import { Dashboard } from '@ttoss/react-dashboard';
100
110
 
101
111
  <Dashboard
112
+ selectedTemplate={selectedTemplate}
102
113
  templates={templates}
103
114
  filters={filters}
104
115
  loading={false}
@@ -111,13 +122,14 @@ import { Dashboard } from '@ttoss/react-dashboard';
111
122
 
112
123
  **Props:**
113
124
 
114
- | Prop | Type | Default | Description |
115
- | ----------------- | -------------------------------------- | ------- | ------------------------------------------ |
116
- | `templates` | `DashboardTemplate[]` | `[]` | Array of dashboard templates |
117
- | `filters` | `DashboardFilter[]` | `[]` | Array of dashboard filters |
118
- | `loading` | `boolean` | `false` | Loading state for the dashboard |
119
- | `headerChildren` | `React.ReactNode` | - | Additional content to render in the header |
120
- | `onFiltersChange` | `(filters: DashboardFilter[]) => void` | - | Callback when filters change |
125
+ | Prop | Type | Default | Description |
126
+ | ------------------ | -------------------------------------- | ------- | ------------------------------------------ |
127
+ | `selectedTemplate` | `DashboardTemplate \| undefined` | - | The template to display in the dashboard |
128
+ | `templates` | `DashboardTemplate[]` | `[]` | Array of dashboard templates |
129
+ | `filters` | `DashboardFilter[]` | `[]` | Array of dashboard filters |
130
+ | `loading` | `boolean` | `false` | Loading state for the dashboard |
131
+ | `headerChildren` | `React.ReactNode` | - | Additional content to render in the header |
132
+ | `onFiltersChange` | `(filters: DashboardFilter[]) => void` | - | Callback when filters change |
121
133
 
122
134
  ### DashboardProvider
123
135
 
@@ -129,6 +141,7 @@ import { DashboardProvider } from '@ttoss/react-dashboard';
129
141
  <DashboardProvider
130
142
  filters={filters}
131
143
  templates={templates}
144
+ selectedTemplate={selectedTemplate}
132
145
  onFiltersChange={handleFiltersChange}
133
146
  >
134
147
  {children}
@@ -137,12 +150,13 @@ import { DashboardProvider } from '@ttoss/react-dashboard';
137
150
 
138
151
  **Props:**
139
152
 
140
- | Prop | Type | Default | Description |
141
- | ----------------- | -------------------------------------- | ------- | ---------------------------- |
142
- | `children` | `React.ReactNode` | - | Child components |
143
- | `filters` | `DashboardFilter[]` | `[]` | Filter state |
144
- | `templates` | `DashboardTemplate[]` | `[]` | Template state |
145
- | `onFiltersChange` | `(filters: DashboardFilter[]) => void` | - | Callback when filters change |
153
+ | Prop | Type | Default | Description |
154
+ | ------------------ | -------------------------------------- | ------- | ---------------------------- |
155
+ | `children` | `React.ReactNode` | - | Child components |
156
+ | `filters` | `DashboardFilter[]` | `[]` | Filter state |
157
+ | `templates` | `DashboardTemplate[]` | `[]` | Template state |
158
+ | `selectedTemplate` | `DashboardTemplate \| undefined` | - | The template to display |
159
+ | `onFiltersChange` | `(filters: DashboardFilter[]) => void` | - | Callback when filters change |
146
160
 
147
161
  ### useDashboard Hook
148
162
 
@@ -163,12 +177,12 @@ const MyComponent = () => {
163
177
 
164
178
  **Returns:**
165
179
 
166
- | Property | Type | Description |
167
- | ------------------ | ---------------------------------------------------- | -------------------------------------------- |
168
- | `filters` | `DashboardFilter[]` | Current filter state |
169
- | `updateFilter` | `(key: string, value: DashboardFilterValue) => void` | Function to update a specific filter by key |
170
- | `templates` | `DashboardTemplate[]` | Current template state |
171
- | `selectedTemplate` | `DashboardTemplate \| undefined` | Currently selected template based on filters |
180
+ | Property | Type | Description |
181
+ | ------------------ | ---------------------------------------------------- | ------------------------------------------- |
182
+ | `filters` | `DashboardFilter[]` | Current filter state |
183
+ | `updateFilter` | `(key: string, value: DashboardFilterValue) => void` | Function to update a specific filter by key |
184
+ | `templates` | `DashboardTemplate[]` | Current template state |
185
+ | `selectedTemplate` | `DashboardTemplate \| undefined` | Currently selected template passed as prop |
172
186
 
173
187
  ### DashboardCard
174
188
 
@@ -437,60 +451,54 @@ import type {
437
451
  import { DashboardFilterType } from '@ttoss/react-dashboard';
438
452
 
439
453
  const App = () => {
440
- const templates: DashboardTemplate[] = [
441
- {
442
- id: 'default',
443
- name: 'Default Dashboard',
444
- grid: [
445
- {
446
- i: 'revenue',
447
- x: 0,
448
- y: 0,
449
- w: 4,
450
- h: 4,
451
- card: {
452
- title: 'Total Revenue',
453
- numberType: 'currency',
454
- type: 'bigNumber',
455
- sourceType: [{ source: 'api' }],
456
- data: {
457
- api: { total: 150000 },
458
- },
459
- trend: {
460
- value: 15.5,
461
- status: 'positive',
462
- },
454
+ const selectedTemplate: DashboardTemplate = {
455
+ id: 'default',
456
+ name: 'Default Dashboard',
457
+ grid: [
458
+ {
459
+ i: 'revenue',
460
+ x: 0,
461
+ y: 0,
462
+ w: 4,
463
+ h: 4,
464
+ card: {
465
+ title: 'Total Revenue',
466
+ numberType: 'currency',
467
+ type: 'bigNumber',
468
+ sourceType: [{ source: 'api' }],
469
+ data: {
470
+ api: { total: 150000 },
471
+ },
472
+ trend: {
473
+ value: 15.5,
474
+ status: 'positive',
463
475
  },
464
476
  },
465
- {
466
- i: 'roas',
467
- x: 4,
468
- y: 0,
469
- w: 4,
470
- h: 4,
471
- card: {
472
- title: 'ROAS',
473
- numberType: 'number',
474
- type: 'bigNumber',
475
- sourceType: [{ source: 'api' }],
476
- data: {
477
- api: { total: 3.5 },
478
- },
479
- variant: 'light-green',
477
+ },
478
+ {
479
+ i: 'roas',
480
+ x: 4,
481
+ y: 0,
482
+ w: 4,
483
+ h: 4,
484
+ card: {
485
+ title: 'ROAS',
486
+ numberType: 'number',
487
+ type: 'bigNumber',
488
+ sourceType: [{ source: 'api' }],
489
+ data: {
490
+ api: { total: 3.5 },
480
491
  },
492
+ variant: 'light-green',
481
493
  },
482
- ],
483
- },
484
- ];
494
+ },
495
+ ],
496
+ };
497
+
498
+ // Optional: Keep templates array if you need to switch between templates
499
+ const templates: DashboardTemplate[] = [selectedTemplate];
485
500
 
486
501
  const filters: DashboardFilter[] = [
487
- {
488
- key: 'template',
489
- type: DashboardFilterType.SELECT,
490
- label: 'Template',
491
- value: 'default',
492
- options: [{ label: 'Default Dashboard', value: 'default' }],
493
- },
494
502
  {
495
503
  key: 'date-range',
496
504
  type: DashboardFilterType.DATE_RANGE,
@@ -525,6 +533,7 @@ const App = () => {
525
533
 
526
534
  return (
527
535
  <Dashboard
536
+ selectedTemplate={selectedTemplate}
528
537
  templates={templates}
529
538
  filters={filters}
530
539
  loading={false}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/react-dashboard",
3
- "version": "0.1.13",
3
+ "version": "0.1.16",
4
4
  "description": "ttoss dashboard module for React apps.",
5
5
  "license": "MIT",
6
6
  "author": "ttoss",
@@ -26,11 +26,11 @@
26
26
  "dependencies": {
27
27
  "react-day-picker": "^9.11.3",
28
28
  "react-grid-layout": "^1.5.2",
29
- "@ttoss/react-i18n": "^2.0.25",
30
- "@ttoss/components": "^2.11.7",
29
+ "@ttoss/components": "^2.12.1",
31
30
  "@ttoss/react-icons": "^0.5.6",
32
- "@ttoss/ui": "^6.4.0",
33
- "@ttoss/forms": "^0.37.1"
31
+ "@ttoss/forms": "^0.37.3",
32
+ "@ttoss/react-i18n": "^2.0.25",
33
+ "@ttoss/ui": "^6.4.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": ">=16.8.0"
package/dist/esm/index.js DELETED
@@ -1,599 +0,0 @@
1
- /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import * as React from 'react';
3
- var __defProp = Object.defineProperty;
4
- var __name = (target, value) => __defProp(target, "name", {
5
- value,
6
- configurable: true
7
- });
8
-
9
- // src/Dashboard.tsx
10
- import { Divider, Flex as Flex6 } from "@ttoss/ui";
11
-
12
- // src/DashboardGrid.tsx
13
- import "react-grid-layout/css/styles.css";
14
- import { Box as Box3, Flex as Flex3, Spinner } from "@ttoss/ui";
15
- import { Responsive, WidthProvider } from "react-grid-layout";
16
-
17
- // src/Cards/BigNumber.tsx
18
- import { Icon } from "@ttoss/react-icons";
19
- import { Box as Box2, Flex as Flex2, Text as Text2 } from "@ttoss/ui";
20
-
21
- // src/Cards/Wrapper.tsx
22
- import { Box, Flex, Text, TooltipIcon } from "@ttoss/ui";
23
- var CardWrapper = /* @__PURE__ */__name(({
24
- title,
25
- children,
26
- description,
27
- variant = "default"
28
- }) => {
29
- const getBackgroundColor = /* @__PURE__ */__name(() => {
30
- switch (variant) {
31
- case "dark":
32
- return "input.background.secondary.default";
33
- case "light-green":
34
- return "feedback.background.positive.default";
35
- case "default":
36
- default:
37
- return "display.background.primary.default";
38
- }
39
- }, "getBackgroundColor");
40
- const getTitleColor = /* @__PURE__ */__name(() => {
41
- switch (variant) {
42
- case "dark":
43
- return "action.text.primary.default";
44
- case "light-green":
45
- return "feedback.text.positive.default";
46
- case "default":
47
- default:
48
- return "display.text.primary.default";
49
- }
50
- }, "getTitleColor");
51
- return /* @__PURE__ */React.createElement(Flex, {
52
- sx: {
53
- flexDirection: "column",
54
- gap: "3",
55
- backgroundColor: getBackgroundColor(),
56
- borderRadius: "lg",
57
- padding: "4",
58
- width: "100%",
59
- height: "100%",
60
- boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.15)"
61
- }
62
- }, /* @__PURE__ */React.createElement(Box, {
63
- sx: {
64
- alignItems: "center",
65
- gap: "2"
66
- }
67
- }, /* @__PURE__ */React.createElement(Text, {
68
- variant: "h5",
69
- sx: {
70
- color: getTitleColor(),
71
- flex: 1,
72
- minWidth: 0
73
- }
74
- }, title), description && /* @__PURE__ */React.createElement(TooltipIcon, {
75
- variant: "info",
76
- icon: "ant-design:info-circle-outlined",
77
- tooltip: {
78
- children: description
79
- },
80
- sx: {
81
- marginLeft: "2",
82
- flexShrink: 0
83
- }
84
- })), /* @__PURE__ */React.createElement(Flex, {
85
- sx: {
86
- flexDirection: "column",
87
- flex: "auto",
88
- height: "100%",
89
- justifyContent: "center"
90
- }
91
- }, children));
92
- }, "CardWrapper");
93
-
94
- // src/Cards/BigNumber.tsx
95
- var formatNumber = /* @__PURE__ */__name((value, type) => {
96
- if (value === void 0 || value === null) {
97
- return "-";
98
- }
99
- switch (type) {
100
- case "currency":
101
- return new Intl.NumberFormat("pt-BR", {
102
- style: "currency",
103
- currency: "BRL"
104
- }).format(value);
105
- case "percentage":
106
- return `${value.toFixed(2)}%`;
107
- case "number":
108
- default:
109
- {
110
- const formatted = new Intl.NumberFormat("pt-BR", {
111
- minimumFractionDigits: 2,
112
- maximumFractionDigits: 2
113
- }).format(value);
114
- return formatted;
115
- }
116
- }
117
- }, "formatNumber");
118
- var getValueColor = /* @__PURE__ */__name((color, variant) => {
119
- if (variant === "dark") {
120
- return "action.text.primary.default";
121
- }
122
- if (variant === "light-green") {
123
- return "feedback.text.positive.default";
124
- }
125
- if (!color) {
126
- return "display.text.primary.default";
127
- }
128
- if (["green", "accent", "positive"].includes(color.toLowerCase())) {
129
- return "display.text.accent.default";
130
- }
131
- return "display.text.primary.default";
132
- }, "getValueColor");
133
- var getTrendColor = /* @__PURE__ */__name(status => {
134
- if (status === "positive") {
135
- return "feedback.text.positive.default";
136
- }
137
- if (status === "negative") {
138
- return "feedback.text.negative.default";
139
- }
140
- return "display.text.primary.default";
141
- }, "getTrendColor");
142
- var BigNumber = /* @__PURE__ */__name(props => {
143
- const total = props.data.api?.total ?? props.data.meta?.total ?? void 0;
144
- const formattedValue = formatNumber(total, props.numberType);
145
- const displayValue = props.numberType === "number" && props.title.toLowerCase().includes("roas") ? `${formattedValue}x` : formattedValue;
146
- const valueColor = getValueColor(props.color, props.variant);
147
- const variant = props.variant || "default";
148
- return /* @__PURE__ */React.createElement(CardWrapper, {
149
- title: props.title,
150
- description: props.description || "",
151
- variant
152
- }, /* @__PURE__ */React.createElement(Flex2, {
153
- sx: {
154
- flexDirection: "column",
155
- gap: "2"
156
- }
157
- }, /* @__PURE__ */React.createElement(Text2, {
158
- sx: {
159
- color: valueColor,
160
- fontSize: "2xl",
161
- fontWeight: "bold",
162
- lineHeight: "1.2"
163
- }
164
- }, displayValue), props.trend && /* @__PURE__ */React.createElement(Flex2, {
165
- sx: {
166
- alignItems: "center",
167
- gap: "1"
168
- }
169
- }, /* @__PURE__ */React.createElement(Box2, {
170
- sx: {
171
- color: getTrendColor(props.trend.status),
172
- display: "flex",
173
- alignItems: "center"
174
- }
175
- }, props.trend.status === "positive" ? /* @__PURE__ */React.createElement(Icon, {
176
- icon: "mdi:arrow-up",
177
- width: 16
178
- }) : props.trend.status === "negative" ? /* @__PURE__ */React.createElement(Icon, {
179
- icon: "mdi:arrow-down",
180
- width: 16
181
- }) : null), ["positive", "negative"].includes(props.trend?.status || "") && /* @__PURE__ */React.createElement(Text2, {
182
- sx: {
183
- color: getTrendColor(props.trend.status),
184
- fontSize: "sm",
185
- fontWeight: "medium"
186
- }
187
- }, props.trend.status === "positive" ? "+" : "", props.trend.value.toFixed(1), "%", " ", props.trend ? "vs. per\xEDodo anterior" : "")), props.additionalInfo && /* @__PURE__ */React.createElement(Text2, {
188
- sx: {
189
- color: getValueColor(props.color, props.variant),
190
- fontSize: "sm",
191
- mt: "1"
192
- }
193
- }, props.additionalInfo), props.status && /* @__PURE__ */React.createElement(Flex2, {
194
- sx: {
195
- alignItems: "center",
196
- gap: "1",
197
- mt: props.trend || props.additionalInfo ? "2" : "1"
198
- }
199
- }, props.status.icon && /* @__PURE__ */React.createElement(Box2, {
200
- sx: {
201
- color: "feedback.text.positive.default",
202
- display: "flex",
203
- alignItems: "center"
204
- }
205
- }, /* @__PURE__ */React.createElement(Icon, {
206
- icon: props.status.icon,
207
- width: 16
208
- })), /* @__PURE__ */React.createElement(Text2, {
209
- sx: {
210
- color: "feedback.text.positive.default",
211
- fontSize: "sm",
212
- fontWeight: "medium"
213
- }
214
- }, props.status.text))));
215
- }, "BigNumber");
216
-
217
- // src/DashboardCard.tsx
218
- var DashboardCard = /* @__PURE__ */__name(props => {
219
- switch (props.type) {
220
- case "bigNumber":
221
- return /* @__PURE__ */React.createElement(BigNumber, props);
222
- default:
223
- return null;
224
- }
225
- }, "DashboardCard");
226
-
227
- // src/DashboardGrid.tsx
228
- var ResponsiveGridLayout = WidthProvider(Responsive);
229
- var DashboardGrid = /* @__PURE__ */__name(({
230
- loading,
231
- selectedTemplate
232
- }) => {
233
- if (!selectedTemplate) {
234
- return null;
235
- }
236
- const breakpoints = {
237
- xs: 0,
238
- sm: 480,
239
- md: 768,
240
- lg: 1024,
241
- xl: 1280,
242
- "2xl": 1536
243
- };
244
- const cols = {
245
- xs: 2,
246
- sm: 2,
247
- md: 12,
248
- lg: 12,
249
- xl: 12,
250
- "2xl": 12
251
- };
252
- const baseLayout = selectedTemplate.grid.map(item => {
253
- const {
254
- card,
255
- ...layout
256
- } = item;
257
- return layout;
258
- });
259
- const layouts = {
260
- xs: baseLayout,
261
- sm: baseLayout,
262
- md: baseLayout,
263
- lg: baseLayout,
264
- xl: baseLayout,
265
- "2xl": baseLayout
266
- };
267
- return /* @__PURE__ */React.createElement(Box3, {
268
- sx: {
269
- width: "100%",
270
- height: "full"
271
- }
272
- }, loading ? /* @__PURE__ */React.createElement(Flex3, {
273
- sx: {
274
- width: "100%",
275
- height: "full",
276
- justifyContent: "center",
277
- alignItems: "center"
278
- }
279
- }, /* @__PURE__ */React.createElement(Spinner, null)) : /* @__PURE__ */React.createElement(ResponsiveGridLayout, {
280
- className: "layout",
281
- layouts,
282
- breakpoints,
283
- cols,
284
- rowHeight: 30,
285
- margin: [10, 10],
286
- containerPadding: [0, 0]
287
- }, selectedTemplate.grid.map(item => {
288
- return /* @__PURE__ */React.createElement("div", {
289
- key: item.i
290
- }, /* @__PURE__ */React.createElement(DashboardCard, item.card));
291
- })));
292
- }, "DashboardGrid");
293
-
294
- // src/DashboardHeader.tsx
295
- import { Flex as Flex5 } from "@ttoss/ui";
296
- import * as React7 from "react";
297
-
298
- // src/DashboardFilters.tsx
299
- import { Flex as Flex4 } from "@ttoss/ui";
300
- import * as React6 from "react";
301
-
302
- // src/DashboardProvider.tsx
303
- import * as React2 from "react";
304
- var DashboardContext = /* @__PURE__ */React2.createContext({
305
- filters: [],
306
- updateFilter: /* @__PURE__ */__name(() => {}, "updateFilter"),
307
- templates: [],
308
- selectedTemplate: void 0
309
- });
310
- var DashboardProvider = /* @__PURE__ */__name(props => {
311
- const {
312
- filters: externalFilters,
313
- templates: externalTemplates,
314
- onFiltersChange,
315
- selectedTemplate
316
- } = props;
317
- const onFiltersChangeRef = React2.useRef(onFiltersChange);
318
- const filtersRef = React2.useRef(externalFilters);
319
- React2.useEffect(() => {
320
- onFiltersChangeRef.current = onFiltersChange;
321
- }, [onFiltersChange]);
322
- React2.useEffect(() => {
323
- filtersRef.current = externalFilters;
324
- }, [externalFilters]);
325
- const updateFilter = React2.useCallback((key, value) => {
326
- const updatedFilters = filtersRef.current.map(filter => {
327
- return filter.key === key ? {
328
- ...filter,
329
- value
330
- } : filter;
331
- });
332
- onFiltersChangeRef.current?.(updatedFilters);
333
- }, []
334
- // Empty deps - we use refs for current values
335
- );
336
- return /* @__PURE__ */React2.createElement(DashboardContext.Provider, {
337
- value: {
338
- filters: externalFilters,
339
- updateFilter,
340
- templates: externalTemplates,
341
- selectedTemplate
342
- }
343
- }, props.children);
344
- }, "DashboardProvider");
345
- var useDashboard = /* @__PURE__ */__name(() => {
346
- const context = React2.useContext(DashboardContext);
347
- if (!context) {
348
- throw new Error("useDashboard must be used within a DashboardProvider");
349
- }
350
- return context;
351
- }, "useDashboard");
352
-
353
- // src/Filters/DateRangeFilter.tsx
354
- import { FormFieldDatePicker } from "@ttoss/forms";
355
- import { FormProvider, useForm } from "@ttoss/forms";
356
- import * as React3 from "react";
357
- var DateRangeFilter = /* @__PURE__ */__name(({
358
- label,
359
- value,
360
- presets,
361
- onChange
362
- }) => {
363
- const formMethods = useForm({
364
- defaultValues: {
365
- dateRange: value
366
- },
367
- mode: "onChange"
368
- });
369
- React3.useEffect(() => {
370
- if (value !== void 0) {
371
- formMethods.setValue("dateRange", value, {
372
- shouldDirty: false
373
- });
374
- }
375
- }, [value, formMethods]);
376
- const currentValue = formMethods.watch("dateRange");
377
- const dateRangesEqual = React3.useCallback((a, b) => {
378
- if (a === b) {
379
- return true;
380
- }
381
- if (!a || !b) {
382
- return false;
383
- }
384
- const aFrom = a.from?.getTime();
385
- const aTo = a.to?.getTime();
386
- const bFrom = b.from?.getTime();
387
- const bTo = b.to?.getTime();
388
- return aFrom === bFrom && aTo === bTo;
389
- }, []);
390
- React3.useEffect(() => {
391
- if (currentValue !== void 0 && !dateRangesEqual(currentValue, value)) {
392
- onChange?.(currentValue);
393
- }
394
- }, [currentValue, value, onChange, dateRangesEqual]);
395
- return /* @__PURE__ */React3.createElement(FormProvider, formMethods, /* @__PURE__ */React3.createElement(FormFieldDatePicker, {
396
- name: "dateRange",
397
- label,
398
- presets
399
- }));
400
- }, "DateRangeFilter");
401
-
402
- // src/Filters/SelectFilter.tsx
403
- import { FormFieldSelect, FormProvider as FormProvider2, useForm as useForm2 } from "@ttoss/forms";
404
- import * as React4 from "react";
405
- var SelectFilter = /* @__PURE__ */__name(props => {
406
- const {
407
- value,
408
- onChange,
409
- label,
410
- options
411
- } = props;
412
- const formMethods = useForm2({
413
- defaultValues: {
414
- value
415
- },
416
- mode: "onChange"
417
- });
418
- React4.useEffect(() => {
419
- const propValue = value;
420
- formMethods.setValue("value", propValue, {
421
- shouldDirty: false
422
- });
423
- }, [value, formMethods]);
424
- const currentValue = formMethods.watch("value");
425
- React4.useEffect(() => {
426
- if (currentValue !== void 0 && currentValue !== value) {
427
- onChange(currentValue);
428
- }
429
- }, [currentValue, value, onChange]);
430
- return /* @__PURE__ */React4.createElement(FormProvider2, formMethods, /* @__PURE__ */React4.createElement(FormFieldSelect, {
431
- name: "value",
432
- label,
433
- options,
434
- sx: {
435
- fontSize: "sm"
436
- }
437
- }));
438
- }, "SelectFilter");
439
-
440
- // src/Filters/TextFilter.tsx
441
- import { FormFieldInput, FormProvider as FormProvider3, useForm as useForm3 } from "@ttoss/forms";
442
- import * as React5 from "react";
443
- var TextFilter = /* @__PURE__ */__name(props => {
444
- const {
445
- value,
446
- onChange,
447
- label,
448
- placeholder
449
- } = props;
450
- const formMethods = useForm3({
451
- defaultValues: {
452
- value: value.toString()
453
- },
454
- mode: "onChange"
455
- });
456
- React5.useEffect(() => {
457
- const stringValue = value.toString();
458
- formMethods.setValue("value", stringValue, {
459
- shouldDirty: false
460
- });
461
- }, [value, formMethods]);
462
- const currentValue = formMethods.watch("value");
463
- React5.useEffect(() => {
464
- if (currentValue !== void 0 && currentValue !== value.toString()) {
465
- onChange(currentValue);
466
- }
467
- }, [currentValue, value, onChange]);
468
- return /* @__PURE__ */React5.createElement(FormProvider3, formMethods, /* @__PURE__ */React5.createElement(FormFieldInput, {
469
- name: "value",
470
- label,
471
- placeholder,
472
- sx: {
473
- fontSize: "sm"
474
- }
475
- }));
476
- }, "TextFilter");
477
-
478
- // src/DashboardFilters.tsx
479
- var DashboardFilterType = /* @__PURE__ */function (DashboardFilterType2) {
480
- DashboardFilterType2["TEXT"] = "text";
481
- DashboardFilterType2["SELECT"] = "select";
482
- DashboardFilterType2["DATE_RANGE"] = "date-range";
483
- DashboardFilterType2["NUMBER"] = "number";
484
- DashboardFilterType2["BOOLEAN"] = "boolean";
485
- return DashboardFilterType2;
486
- }({});
487
- var DashboardFilters = /* @__PURE__ */__name(() => {
488
- const {
489
- filters,
490
- updateFilter
491
- } = useDashboard();
492
- const onChangeHandlers = React6.useMemo(() => {
493
- const handlers = /* @__PURE__ */new Map();
494
- for (const filter of filters) {
495
- handlers.set(filter.key, value => {
496
- updateFilter(filter.key, value);
497
- });
498
- }
499
- return handlers;
500
- }, [filters, updateFilter]);
501
- return /* @__PURE__ */React6.createElement(Flex4, {
502
- sx: {
503
- gap: "2",
504
- flexDirection: "row",
505
- "@media (max-width: 768px)": {
506
- flexWrap: "wrap"
507
- }
508
- }
509
- }, filters.map(filter => {
510
- const onChange = onChangeHandlers.get(filter.key);
511
- if (!onChange) {
512
- return null;
513
- }
514
- switch (filter.type) {
515
- case "text":
516
- return /* @__PURE__ */React6.createElement(TextFilter, {
517
- key: filter.key,
518
- name: filter.key,
519
- label: filter.label,
520
- value: filter.value,
521
- placeholder: filter.placeholder,
522
- onChange
523
- });
524
- case "select":
525
- return /* @__PURE__ */React6.createElement(SelectFilter, {
526
- key: filter.key,
527
- name: filter.key,
528
- label: filter.label,
529
- value: filter.value,
530
- options: filter.options ?? [],
531
- onChange: /* @__PURE__ */__name(value => {
532
- onChange(value);
533
- }, "onChange")
534
- });
535
- case "date-range":
536
- return /* @__PURE__ */React6.createElement(DateRangeFilter, {
537
- label: filter.label,
538
- key: filter.key,
539
- value: filter.value,
540
- presets: filter.presets,
541
- onChange: /* @__PURE__ */__name(range => {
542
- onChange(range);
543
- }, "onChange")
544
- });
545
- default:
546
- return null;
547
- }
548
- }));
549
- }, "DashboardFilters");
550
-
551
- // src/DashboardHeader.tsx
552
- var DashboardHeader = /* @__PURE__ */__name(({
553
- children
554
- }) => {
555
- return /* @__PURE__ */React7.createElement(Flex5, {
556
- sx: {
557
- padding: "2"
558
- }
559
- }, /* @__PURE__ */React7.createElement(DashboardFilters, null), children);
560
- }, "DashboardHeader");
561
-
562
- // src/Dashboard.tsx
563
- var DashboardContent = /* @__PURE__ */__name(({
564
- loading = false,
565
- headerChildren,
566
- selectedTemplate
567
- }) => {
568
- return /* @__PURE__ */React.createElement(Flex6, {
569
- sx: {
570
- flexDirection: "column",
571
- gap: "5",
572
- padding: "2",
573
- width: "100%"
574
- }
575
- }, /* @__PURE__ */React.createElement(DashboardHeader, null, headerChildren), /* @__PURE__ */React.createElement(Divider, null), /* @__PURE__ */React.createElement(DashboardGrid, {
576
- loading,
577
- selectedTemplate
578
- }));
579
- }, "DashboardContent");
580
- var Dashboard = /* @__PURE__ */__name(({
581
- selectedTemplate,
582
- loading = false,
583
- templates = [],
584
- filters = [],
585
- headerChildren,
586
- onFiltersChange
587
- }) => {
588
- return /* @__PURE__ */React.createElement(DashboardProvider, {
589
- filters,
590
- templates,
591
- onFiltersChange,
592
- selectedTemplate
593
- }, /* @__PURE__ */React.createElement(DashboardContent, {
594
- loading,
595
- headerChildren,
596
- selectedTemplate
597
- }));
598
- }, "Dashboard");
599
- export { Dashboard, DashboardCard, DashboardFilterType, DashboardFilters, DashboardGrid, DashboardHeader, DashboardProvider, useDashboard };
package/dist/index.d.ts DELETED
@@ -1,126 +0,0 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as React from 'react';
3
- import ReactGridLayout from 'react-grid-layout';
4
- import { DateRange } from '@ttoss/components/DatePicker';
5
-
6
- type CardNumberType = 'number' | 'percentage' | 'currency';
7
- type CardSourceType = {
8
- source: 'meta' | 'oneclickads' | 'api';
9
- level?: 'adAccount' | 'campaign' | 'adSet' | 'ad';
10
- };
11
- type DashboardCardType = 'bigNumber' | 'pieChart' | 'barChart' | 'lineChart' | 'table' | 'list';
12
- type DashboardCardData = {
13
- meta?: {
14
- total?: number;
15
- daily?: number[];
16
- };
17
- api?: {
18
- total?: number;
19
- daily?: number[];
20
- };
21
- };
22
- type CardVariant = 'default' | 'dark' | 'light-green';
23
- type TrendIndicator = {
24
- value: number;
25
- status?: 'positive' | 'negative' | 'neutral';
26
- type?: 'higher' | 'lower';
27
- };
28
- type StatusIndicator = {
29
- text: string;
30
- icon?: string;
31
- };
32
- type SourceType = CardSourceType['source'];
33
- type MetricsRecord = {
34
- [K in SourceType]: {
35
- [P in K]: string[];
36
- } & Partial<Record<Exclude<SourceType, K>, string[]>>;
37
- }[SourceType];
38
- interface DashboardCard {
39
- title: string;
40
- description?: string;
41
- icon?: string;
42
- color?: string;
43
- variant?: CardVariant;
44
- numberType: CardNumberType;
45
- type: DashboardCardType;
46
- sourceType: CardSourceType[];
47
- labels?: Array<string | number>;
48
- data: DashboardCardData;
49
- trend?: TrendIndicator;
50
- additionalInfo?: string;
51
- status?: StatusIndicator;
52
- metrics?: MetricsRecord[];
53
- }
54
- declare const DashboardCard: (props: DashboardCard) => react_jsx_runtime.JSX.Element | null;
55
-
56
- type DashboardFilterValue = string | number | boolean | {
57
- from: Date;
58
- to: Date;
59
- };
60
- declare enum DashboardFilterType {
61
- TEXT = "text",
62
- SELECT = "select",
63
- DATE_RANGE = "date-range",
64
- NUMBER = "number",
65
- BOOLEAN = "boolean"
66
- }
67
- type DashboardFilter = {
68
- key: string;
69
- type: DashboardFilterType;
70
- label: string;
71
- placeholder?: string;
72
- value: DashboardFilterValue;
73
- onChange?: (value: DashboardFilterValue) => void;
74
- options?: {
75
- label: string;
76
- value: string | number | boolean;
77
- }[];
78
- presets?: {
79
- label: string;
80
- getValue: () => DateRange;
81
- }[];
82
- };
83
- declare const DashboardFilters: () => react_jsx_runtime.JSX.Element;
84
-
85
- type DashboardGridItem = ReactGridLayout.Layout & {
86
- card: DashboardCard;
87
- };
88
- interface DashboardTemplate {
89
- id: string;
90
- name: string;
91
- description?: string;
92
- grid: DashboardGridItem[];
93
- }
94
- declare const Dashboard: ({ selectedTemplate, loading, templates, filters, headerChildren, onFiltersChange, }: {
95
- selectedTemplate?: DashboardTemplate;
96
- loading?: boolean;
97
- headerChildren?: React.ReactNode;
98
- templates?: DashboardTemplate[];
99
- filters?: DashboardFilter[];
100
- onFiltersChange?: (filters: DashboardFilter[]) => void;
101
- }) => react_jsx_runtime.JSX.Element;
102
-
103
- declare const DashboardGrid: ({ loading, selectedTemplate, }: {
104
- loading: boolean;
105
- selectedTemplate?: DashboardTemplate;
106
- }) => react_jsx_runtime.JSX.Element | null;
107
-
108
- declare const DashboardHeader: ({ children, }: {
109
- children?: React.ReactNode;
110
- }) => react_jsx_runtime.JSX.Element;
111
-
112
- declare const DashboardProvider: (props: {
113
- children: React.ReactNode;
114
- filters: DashboardFilter[];
115
- templates: DashboardTemplate[];
116
- onFiltersChange?: (filters: DashboardFilter[]) => void;
117
- selectedTemplate?: DashboardTemplate;
118
- }) => react_jsx_runtime.JSX.Element;
119
- declare const useDashboard: () => {
120
- filters: DashboardFilter[];
121
- updateFilter: (key: string, value: DashboardFilterValue) => void;
122
- templates: DashboardTemplate[];
123
- selectedTemplate: DashboardTemplate | undefined;
124
- };
125
-
126
- export { Dashboard, DashboardCard, type DashboardFilter, DashboardFilterType, type DashboardFilterValue, DashboardFilters, DashboardGrid, type DashboardGridItem, DashboardHeader, DashboardProvider, type DashboardTemplate, useDashboard };