@ttoss/react-dashboard 0.1.2 → 0.1.3

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