namirasoft-site-react 1.4.560 → 1.4.561

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/SKILL.md +1 -1
  2. package/dist/ColorOperation.d.ts +27 -0
  3. package/dist/ColorOperation.js +145 -0
  4. package/dist/ColorOperation.js.map +1 -0
  5. package/dist/components/NSBoxBaseCombo.d.ts +2 -0
  6. package/dist/components/NSBoxBaseCombo.js +16 -14
  7. package/dist/components/NSBoxBaseCombo.js.map +1 -1
  8. package/dist/components/NSBoxCombo.d.ts +4 -4
  9. package/dist/components/NSBoxCombo.js +2 -2
  10. package/dist/components/NSBoxCombo.js.map +1 -1
  11. package/dist/components/NSBoxOptions.d.ts +32 -0
  12. package/dist/components/NSBoxOptions.js +105 -0
  13. package/dist/components/NSBoxOptions.js.map +1 -0
  14. package/dist/components/NSBoxOptions.module.css +54 -0
  15. package/dist/components/{NSChartColumn.d.ts → NSChartBar.d.ts} +6 -2
  16. package/dist/components/NSChartBar.js +93 -0
  17. package/dist/components/NSChartBar.js.map +1 -0
  18. package/dist/components/NSChartDoughnut.d.ts +3 -0
  19. package/dist/components/NSChartDoughnut.js +22 -20
  20. package/dist/components/NSChartDoughnut.js.map +1 -1
  21. package/dist/components/NSChartLine.d.ts +21 -0
  22. package/dist/components/NSChartLine.js +76 -0
  23. package/dist/components/NSChartLine.js.map +1 -0
  24. package/dist/components/NSChartPie.d.ts +3 -0
  25. package/dist/components/NSChartPie.js +20 -21
  26. package/dist/components/NSChartPie.js.map +1 -1
  27. package/dist/components/NSPagination.js +9 -8
  28. package/dist/components/NSPagination.js.map +1 -1
  29. package/dist/components/NSPagination.module.css +1 -0
  30. package/dist/components/NSTable.d.ts +1 -0
  31. package/dist/components/NSTable.js +9 -3
  32. package/dist/components/NSTable.js.map +1 -1
  33. package/dist/components/NSTableChart.d.ts +49 -0
  34. package/dist/components/NSTableChart.js +335 -0
  35. package/dist/components/NSTableChart.js.map +1 -0
  36. package/dist/components/NSTableChart.module.css +120 -0
  37. package/dist/main.d.ts +5 -2
  38. package/dist/main.js +5 -2
  39. package/dist/main.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/ColorOperation.ts +154 -0
  42. package/src/components/NSBoxBaseCombo.tsx +14 -10
  43. package/src/components/NSBoxCombo.tsx +2 -2
  44. package/src/components/NSBoxOptions.module.css +54 -0
  45. package/src/components/NSBoxOptions.tsx +183 -0
  46. package/src/components/NSChartBar.tsx +135 -0
  47. package/src/components/NSChartDoughnut.tsx +26 -24
  48. package/src/components/NSChartLine.tsx +111 -0
  49. package/src/components/NSChartPie.tsx +23 -23
  50. package/src/components/NSPagination.module.css +1 -0
  51. package/src/components/NSPagination.tsx +14 -13
  52. package/src/components/NSTable.tsx +17 -1
  53. package/src/components/NSTableChart.module.css +120 -0
  54. package/src/components/NSTableChart.tsx +588 -0
  55. package/src/main.ts +5 -2
  56. package/dist/components/NSChartColumn.js +0 -95
  57. package/dist/components/NSChartColumn.js.map +0 -1
  58. package/dist/components/NSChartColumn.module.css +0 -8
  59. package/dist/components/NSChartTable.d.ts +0 -15
  60. package/dist/components/NSChartTable.js +0 -63
  61. package/dist/components/NSChartTable.js.map +0 -1
  62. package/dist/components/NSChartTable.module.css +0 -22
  63. package/src/components/NSChartColumn.module.css +0 -8
  64. package/src/components/NSChartColumn.tsx +0 -131
  65. package/src/components/NSChartTable.module.css +0 -22
  66. package/src/components/NSChartTable.tsx +0 -95
@@ -0,0 +1,588 @@
1
+ "use client";
2
+ import { IStorageLocal } from "namirasoft-core";
3
+ import { Component, createRef } from "react";
4
+ import { IBaseComponentProps } from "../props/IBaseComponentProps";
5
+ import { NSBoxBoolean } from "./NSBoxBoolean";
6
+ import { NSBoxCombo } from "./NSBoxCombo";
7
+ import { NSBoxOptions } from "./NSBoxOptions";
8
+ import { NSButton } from "./NSButton";
9
+ import { NSButtonBlue } from "./NSButtonBlue";
10
+ import { NSChartBar, NSChartBarMode } from "./NSChartBar";
11
+ import { NSChartDoughnut } from "./NSChartDoughnut";
12
+ import { NSChartLine } from "./NSChartLine";
13
+ import { NSColumn } from "./NSColumn";
14
+ import { NSNoData } from "./NSNoData";
15
+ import { TableColumnInfo } from "./NSTable";
16
+ import Styles from "./NSTableChart.module.css";
17
+
18
+ export type NSTableChartType = "bar" | "hbar" | "line" | "area" | "doughnut";
19
+ export type NSTableChartRowSource = "page" | "selected";
20
+ export type NSTableChartAggregate = "sum" | "average" | "count" | "min" | "max";
21
+
22
+ const CHART_TYPES: { type: NSTableChartType, text: string }[] = [
23
+ { type: "bar", text: "Bar" },
24
+ { type: "hbar", text: "Horizontal Bar" },
25
+ { type: "line", text: "Line" },
26
+ { type: "area", text: "Area" },
27
+ { type: "doughnut", text: "Doughnut" },
28
+ ];
29
+
30
+ const BAR_MODES: { mode: NSChartBarMode, text: string }[] = [
31
+ { mode: "grouped", text: "Grouped" },
32
+ { mode: "stacked", text: "Stacked" },
33
+ { mode: "percent", text: "Percent" },
34
+ ];
35
+
36
+ const AGGREGATES: { value: NSTableChartAggregate, text: string }[] = [
37
+ { value: "sum", text: "Sum" },
38
+ { value: "average", text: "Average" },
39
+ { value: "count", text: "Count" },
40
+ { value: "min", text: "Min" },
41
+ { value: "max", text: "Max" },
42
+ ];
43
+
44
+ const NUMERIC_TYPES = ["number", "integer", "int", "float", "double", "decimal", "long", "money", "percent", "percentage", "bytes", "duration"];
45
+
46
+ export interface NSTableChartProps<RowType> extends IBaseComponentProps
47
+ {
48
+ name: string;
49
+ columns: TableColumnInfo[];
50
+ rows: RowType[];
51
+ selectedRows: RowType[];
52
+ onClose: () => void;
53
+ }
54
+
55
+ interface NSTableChartState
56
+ {
57
+ chartType: NSTableChartType;
58
+ barMode: NSChartBarMode;
59
+ aggregate: NSTableChartAggregate;
60
+ rowSource: NSTableChartRowSource;
61
+ xColumn: string;
62
+ yColumns: string[];
63
+ }
64
+
65
+ interface NSTableChartSettings
66
+ {
67
+ chartType?: NSTableChartType;
68
+ barMode?: NSChartBarMode;
69
+ aggregate?: NSTableChartAggregate;
70
+ rowSource?: NSTableChartRowSource;
71
+ xColumn?: string;
72
+ yColumns?: string[];
73
+ }
74
+
75
+ export class NSTableChart<RowType> extends Component<NSTableChartProps<RowType>, NSTableChartState>
76
+ {
77
+ private chartContainer = createRef<HTMLDivElement>();
78
+ private previousBodyOverflow = "";
79
+ private Storage = new IStorageLocal();
80
+
81
+ constructor(props: NSTableChartProps<RowType>)
82
+ {
83
+ super(props);
84
+ let numeric = this.getNumericColumns();
85
+ let nonNumeric = props.columns.filter(column => !this.isNumericColumn(column));
86
+ let defaultX = (nonNumeric[0] ?? props.columns[0])?.name ?? "";
87
+ let defaultY = numeric.length > 0 ? [numeric[0].name] : [];
88
+
89
+ let saved = this.loadSettings();
90
+ let chartType: NSTableChartType = CHART_TYPES.some(item => item.type === saved?.chartType) ? saved!.chartType! : "bar";
91
+ let barMode: NSChartBarMode = BAR_MODES.some(item => item.mode === saved?.barMode) ? saved!.barMode! : "grouped";
92
+ let aggregate: NSTableChartAggregate = AGGREGATES.some(item => item.value === saved?.aggregate) ? saved!.aggregate! : "sum";
93
+ let rowSource: NSTableChartRowSource = saved?.rowSource === "selected" ? "selected" : "page";
94
+ let xColumn = (saved?.xColumn && this.getColumn(saved.xColumn)) ? saved.xColumn : defaultX;
95
+ let savedY = (saved?.yColumns ?? []).filter((name: string) => numeric.some(column => column.name === name));
96
+ let yColumns = savedY.length > 0 ? savedY : defaultY;
97
+ if (chartType === "doughnut" && yColumns.length > 1)
98
+ yColumns = [yColumns[0]];
99
+
100
+ this.state = {
101
+ chartType,
102
+ barMode,
103
+ aggregate,
104
+ rowSource,
105
+ xColumn,
106
+ yColumns,
107
+ };
108
+ this.download = this.download.bind(this);
109
+ }
110
+
111
+ override componentDidMount()
112
+ {
113
+ this.previousBodyOverflow = document.body.style.overflow;
114
+ document.body.style.overflow = "hidden";
115
+ }
116
+
117
+ override componentWillUnmount()
118
+ {
119
+ document.body.style.overflow = this.previousBodyOverflow;
120
+ }
121
+
122
+ override componentDidUpdate(_prevProps: NSTableChartProps<RowType>, prevState: NSTableChartState)
123
+ {
124
+ if (
125
+ prevState.chartType !== this.state.chartType ||
126
+ prevState.barMode !== this.state.barMode ||
127
+ prevState.aggregate !== this.state.aggregate ||
128
+ prevState.rowSource !== this.state.rowSource ||
129
+ prevState.xColumn !== this.state.xColumn ||
130
+ prevState.yColumns !== this.state.yColumns
131
+ )
132
+ this.saveSettings();
133
+ }
134
+
135
+ private settingsKey(): string
136
+ {
137
+ return `ns_table_chart_${this.props.name}`;
138
+ }
139
+
140
+ private loadSettings(): NSTableChartSettings | null
141
+ {
142
+ try
143
+ {
144
+ let raw = this.Storage.get(this.settingsKey(), "");
145
+ return raw ? JSON.parse(raw) as NSTableChartSettings : null;
146
+ }
147
+ catch (e)
148
+ {
149
+ return null;
150
+ }
151
+ }
152
+
153
+ private saveSettings(): void
154
+ {
155
+ try
156
+ {
157
+ let { chartType, barMode, aggregate, rowSource, xColumn, yColumns } = this.state;
158
+ this.Storage.set(this.settingsKey(), JSON.stringify({ chartType, barMode, aggregate, rowSource, xColumn, yColumns }));
159
+ }
160
+ catch (e) { }
161
+ }
162
+
163
+ private isNumericColumn(column: TableColumnInfo): boolean
164
+ {
165
+ return NUMERIC_TYPES.includes((column.type ?? "").toLowerCase());
166
+ }
167
+
168
+ private getNumericColumns(): TableColumnInfo[]
169
+ {
170
+ return this.props.columns.filter(column => this.isNumericColumn(column));
171
+ }
172
+
173
+ private getColumn(name: string): TableColumnInfo | undefined
174
+ {
175
+ return this.props.columns.find(column => column.name === name);
176
+ }
177
+
178
+ private getTableTitle(): string
179
+ {
180
+ return this.props.columns[0]?.table?.text ?? this.props.name;
181
+ }
182
+
183
+ private getActiveRows(): RowType[]
184
+ {
185
+ return this.state.rowSource === "selected" ? this.props.selectedRows : this.props.rows;
186
+ }
187
+
188
+ private toNumber(value: any): number
189
+ {
190
+ let n = Number(value);
191
+ return isFinite(n) ? n : 0;
192
+ }
193
+
194
+ private labelOf(row: RowType, column: TableColumnInfo | undefined): string
195
+ {
196
+ if (!column)
197
+ return "";
198
+ let value = (row as any)[column.name];
199
+ if (value === null || value === undefined)
200
+ return "";
201
+ return String(value);
202
+ }
203
+
204
+ private aggregate(rows: RowType[], xCol: TableColumnInfo | undefined, yCols: TableColumnInfo[]): { labels: string[], series: number[][] }
205
+ {
206
+ let labels: string[] = [];
207
+ let indexByLabel = new Map<string, number>();
208
+ let stats: { sum: number, count: number, min: number, max: number }[][] = yCols.map(() => []);
209
+ rows.forEach(row =>
210
+ {
211
+ let label = this.labelOf(row, xCol);
212
+ let index = indexByLabel.get(label);
213
+ if (index === undefined)
214
+ {
215
+ index = labels.length;
216
+ indexByLabel.set(label, index);
217
+ labels.push(label);
218
+ stats.forEach(serie => serie[index as number] = { sum: 0, count: 0, min: Infinity, max: -Infinity });
219
+ }
220
+ yCols.forEach((column, s) =>
221
+ {
222
+ let raw = (row as any)[column.name];
223
+ if (raw === null || raw === undefined || raw === "")
224
+ return;
225
+ let value = this.toNumber(raw);
226
+ let cell = stats[s][index as number];
227
+ cell.sum += value;
228
+ cell.count += 1;
229
+ cell.min = Math.min(cell.min, value);
230
+ cell.max = Math.max(cell.max, value);
231
+ });
232
+ });
233
+
234
+ let series = stats.map(serie => serie.map(cell => this.applyAggregate(cell)));
235
+
236
+ let order = labels.map((_, index) => index);
237
+ order.sort((a, b) => this.compareLabels(labels[a], labels[b], xCol));
238
+ return {
239
+ labels: order.map(index => labels[index]),
240
+ series: series.map(serie => order.map(index => serie[index])),
241
+ };
242
+ }
243
+
244
+ private applyAggregate(cell: { sum: number, count: number, min: number, max: number }): number
245
+ {
246
+ switch (this.state.aggregate)
247
+ {
248
+ case "sum":
249
+ return cell.sum;
250
+ case "count":
251
+ return cell.count;
252
+ case "average":
253
+ return cell.count ? cell.sum / cell.count : 0;
254
+ case "min":
255
+ return cell.count ? cell.min : 0;
256
+ case "max":
257
+ return cell.count ? cell.max : 0;
258
+ default:
259
+ return cell.sum;
260
+ }
261
+ }
262
+
263
+ private formatValueFor(yCols: TableColumnInfo[]): (value: number) => string
264
+ {
265
+ let aggregate = this.state.aggregate;
266
+ let formatter = yCols[0]?.formatter;
267
+ return (value: number) =>
268
+ {
269
+ if (aggregate === "count")
270
+ return Math.round(value).toLocaleString();
271
+ try
272
+ {
273
+ let out = (formatter as any)?.format(value);
274
+ if (typeof out === "string")
275
+ return out;
276
+ }
277
+ catch (e) { }
278
+ return value.toLocaleString();
279
+ };
280
+ }
281
+
282
+ private compareLabels(a: string, b: string, xCol: TableColumnInfo | undefined): number
283
+ {
284
+ if (xCol && this.isNumericColumn(xCol))
285
+ return this.toNumber(a) - this.toNumber(b);
286
+ if (xCol && /(date|time)/.test((xCol.type ?? "").toLowerCase()))
287
+ {
288
+ let da = Date.parse(a);
289
+ let db = Date.parse(b);
290
+ if (!isNaN(da) && !isNaN(db))
291
+ return da - db;
292
+ }
293
+ return a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" });
294
+ }
295
+
296
+ private download()
297
+ {
298
+ let container = this.chartContainer.current;
299
+ if (!container)
300
+ return;
301
+ let canvas = container.querySelector("canvas");
302
+ if (!canvas)
303
+ return;
304
+ let link = document.createElement("a");
305
+ link.href = canvas.toDataURL("image/png");
306
+ link.download = this.props.name + "_chart.png";
307
+ link.click();
308
+ }
309
+
310
+ private renderChart()
311
+ {
312
+ let { chartType, xColumn, yColumns } = this.state;
313
+ let rows = this.getActiveRows();
314
+
315
+ let xCol = this.getColumn(xColumn);
316
+ let yCols = yColumns.map(name => this.getColumn(name)).filter(Boolean) as TableColumnInfo[];
317
+
318
+ if (rows.length === 0)
319
+ return <NSNoData lable={this.state.rowSource === "selected" ? "No selected rows" : "No Data"} />;
320
+ if (yCols.length === 0)
321
+ return <div className={Styles.ns_chart_message}>Select at least one numeric series for the Y-axis.</div>;
322
+
323
+ let { labels, series } = this.aggregate(rows, xCol, yCols);
324
+
325
+ let dataset = yCols.map((column, s) => ({ label: column.text, data: series[s] }));
326
+ let formatValue = this.formatValueFor(yCols);
327
+
328
+ if (chartType === "bar" || chartType === "hbar")
329
+ {
330
+ let max = 0;
331
+ labels.forEach((_, index) =>
332
+ {
333
+ if (this.state.barMode === "stacked")
334
+ {
335
+ let sum = 0;
336
+ dataset.forEach(item => sum += item.data[index] ?? 0);
337
+ max = Math.max(max, sum);
338
+ }
339
+ else
340
+ dataset.forEach(item => max = Math.max(max, item.data[index] ?? 0));
341
+ });
342
+ max = max <= 0 ? 1 : Math.ceil(max * 1.1);
343
+ return (
344
+ <NSChartBar
345
+ labels={labels}
346
+ dataset={dataset}
347
+ range={{ min: 0, max }}
348
+ mode={this.state.barMode}
349
+ horizontal={chartType === "hbar"}
350
+ xTitle={xCol?.text}
351
+ formatValue={formatValue}
352
+ yGrid
353
+ style={{ width: "100%" }}
354
+ />
355
+ );
356
+ }
357
+
358
+ if (chartType === "line" || chartType === "area")
359
+ {
360
+ let max = 0;
361
+ dataset.forEach(item => item.data.forEach(value => max = Math.max(max, value)));
362
+ max = max <= 0 ? 1 : Math.ceil(max * 1.1);
363
+ return (
364
+ <NSChartLine
365
+ labels={labels}
366
+ dataset={dataset}
367
+ range={{ min: 0, max }}
368
+ area={chartType === "area"}
369
+ xTitle={xCol?.text}
370
+ formatValue={formatValue}
371
+ yGrid
372
+ style={{ width: "100%" }}
373
+ />
374
+ );
375
+ }
376
+
377
+ let datas = series[0];
378
+
379
+ return (
380
+ <NSChartDoughnut
381
+ title={yCols[0]?.text ?? ""}
382
+ labels={labels}
383
+ datas={datas}
384
+ labelTitle={xCol?.text}
385
+ valueTitle={yCols[0]?.text}
386
+ formatValue={formatValue}
387
+ style={{ width: "100%", height: "100%", display: "flex", justifyContent: "center" }}
388
+ />
389
+ );
390
+ }
391
+
392
+ override render()
393
+ {
394
+ let { chartType, barMode, xColumn, yColumns } = this.state;
395
+ let numericColumns = this.getNumericColumns();
396
+ let isSingleSeries = chartType === "doughnut";
397
+
398
+ return (
399
+ <div
400
+ id={this.props.id}
401
+ className={[Styles.ns_chart_overlay, ...(this.props.classList ?? [])].join(" ")}
402
+ style={this.props.style}
403
+ >
404
+ <div className={Styles.ns_chart_modal}>
405
+ <div className={Styles.ns_chart_header}>
406
+ <span className={Styles.ns_chart_title}>
407
+ Chart{this.getTableTitle() ? ` - ${this.getTableTitle()}` : ""}
408
+ </span>
409
+ <NSButton
410
+ icon={{ src: "https://static.namirasoft.com/image/concept/close/blue.svg", alt: "close" }}
411
+ onClick={{
412
+ action: this.props.onClose,
413
+ showLoading: false
414
+ }}
415
+ style={{ width: 24, height: 24, boxShadow: "none" }}
416
+ />
417
+ </div>
418
+ <div className={Styles.ns_chart_body}>
419
+ <div className={Styles.ns_chart_canvas} ref={this.chartContainer}>
420
+ {this.renderChart()}
421
+ </div>
422
+ <NSColumn classList={[Styles.ns_chart_panel]}>
423
+ <NSBoxCombo
424
+ title="Chart Type"
425
+ required={false}
426
+ multiple={false}
427
+ searchable={false}
428
+ clearable={false}
429
+ reloadable={false}
430
+ defaultValue={chartType}
431
+ getOptions={() => CHART_TYPES.map(item => ({ value: item.type, title: item.text }))}
432
+ onChanged={(box) =>
433
+ {
434
+ let value = box.getValue(false) as string | null;
435
+ if (!value)
436
+ return;
437
+ let nextType = value as NSTableChartType;
438
+ let nextY = nextType === "doughnut" && yColumns.length > 1
439
+ ? [yColumns[0]]
440
+ : yColumns;
441
+ this.setState({ chartType: nextType, yColumns: nextY });
442
+ }}
443
+ menu={{
444
+ builtin: {
445
+ copy: { enabled: false, getValue: () => "" },
446
+ delete: { enabled: false, onDelete: () => { } },
447
+ },
448
+ items: []
449
+ }}
450
+ />
451
+
452
+ {
453
+ (chartType === "bar" || chartType === "hbar") && yColumns.length > 1 &&
454
+ <NSBoxOptions
455
+ key="bar-mode"
456
+ title="Bar Mode"
457
+ multiple={false}
458
+ required={false}
459
+ defaultValue={barMode}
460
+ options={BAR_MODES.map(item => ({ value: item.mode, title: item.text }))}
461
+ onChanged={(box) =>
462
+ {
463
+ let value = box.getValue(false) as string | null;
464
+ if (value)
465
+ this.setState({ barMode: value as NSChartBarMode });
466
+ }}
467
+ menu={{
468
+ builtin: {
469
+ copy: { enabled: false, getValue: () => "" },
470
+ delete: { enabled: false, onDelete: () => { } },
471
+ },
472
+ items: []
473
+ }}
474
+ input={{ style: { minHeight: "auto", border: "none", padding: "8px 0 0" } }}
475
+ />
476
+ }
477
+
478
+ <NSBoxCombo
479
+ title="Label (X-Axis)"
480
+ multiple={false}
481
+ required={false}
482
+ reloadable={false}
483
+ clearable={false}
484
+ defaultValue={xColumn}
485
+ getOptions={() => this.props.columns.map(column => ({ value: column.name, title: column.text }))}
486
+ onChanged={(box) =>
487
+ {
488
+ let value = box.getValue(false) as string | null;
489
+ if (value)
490
+ this.setState({ xColumn: value });
491
+ }}
492
+ menu={{
493
+ builtin: {
494
+ copy: { enabled: false, getValue: () => "" },
495
+ delete: { enabled: false, onDelete: () => { } },
496
+ },
497
+ items: []
498
+ }}
499
+ />
500
+
501
+ <NSBoxCombo
502
+ key={isSingleSeries ? "y-single" : "y-multi"}
503
+ title={"Series (Y-Axis)"}
504
+ multiple={!isSingleSeries}
505
+ required={false}
506
+ clearable={false}
507
+ reloadable={false}
508
+ defaultValue={isSingleSeries ? yColumns[0] : yColumns}
509
+ getOptions={() => numericColumns.map(column => ({ value: column.name, title: column.text }))}
510
+ onChanged={(box) =>
511
+ {
512
+ let value = box.getValue(false);
513
+ let next = Array.isArray(value) ? value : (value ? [value] : []);
514
+ this.setState({ yColumns: next });
515
+ }}
516
+ menu={{
517
+ builtin: {
518
+ copy: { enabled: false, getValue: () => "" },
519
+ delete: { enabled: false, onDelete: () => { } },
520
+ },
521
+ items: []
522
+ }}
523
+ />
524
+
525
+ <NSBoxOptions
526
+ title="Aggregate"
527
+ multiple={false}
528
+ required={false}
529
+ defaultValue={this.state.aggregate}
530
+ options={AGGREGATES.map(item => ({ value: item.value, title: item.text }))}
531
+ onChanged={(box) =>
532
+ {
533
+ let value = box.getValue(false) as string | null;
534
+ if (value)
535
+ this.setState({ aggregate: value as NSTableChartAggregate });
536
+ }}
537
+ menu={{
538
+ builtin: {
539
+ copy: { enabled: false, getValue: () => "" },
540
+ delete: { enabled: false, onDelete: () => { } },
541
+ },
542
+ items: []
543
+ }}
544
+ input={{ style: { border: "none", padding: "8px 0 0" } }}
545
+ />
546
+
547
+ {
548
+ numericColumns.length === 0 &&
549
+ <div className={Styles.ns_chart_hint}>No numeric columns available.</div>
550
+ }
551
+
552
+ {
553
+ isSingleSeries &&
554
+ <div className={Styles.ns_chart_hint}>Doughnut charts use a single series.</div>
555
+ }
556
+
557
+ <NSBoxBoolean
558
+ title="Only selected rows "
559
+ required={false}
560
+ defaultValue={false}
561
+ hideHeader={true}
562
+ onChanged={(box) =>
563
+ {
564
+ let nextSource: NSTableChartRowSource = box.getValue(false) === true ? "selected" : "page";
565
+ if (nextSource !== this.state.rowSource)
566
+ this.setState({ rowSource: nextSource });
567
+ }}
568
+ />
569
+
570
+ <NSButtonBlue
571
+ title="Download PNG"
572
+ onClick={{
573
+ action: (onFinished) =>
574
+ {
575
+ this.download();
576
+ onFinished();
577
+ },
578
+ showLoading: false,
579
+ }}
580
+ style={{ minHeight: 48, marginTop: "auto" }}
581
+ />
582
+ </NSColumn>
583
+ </div>
584
+ </div>
585
+ </div>
586
+ );
587
+ }
588
+ }
package/src/main.ts CHANGED
@@ -38,6 +38,7 @@ export * from "./components/NSBoxMoney";
38
38
  export * from "./components/NSBoxSensitive";
39
39
  export * from "./components/NSBoxPhone";
40
40
  export * from "./components/NSBoxRadio";
41
+ export * from "./components/NSBoxOptions";
41
42
  export * from "./components/NSBoxSchemaBase";
42
43
  export * from "./components/NSBoxSchemaVariable";
43
44
  export * from "./components/NSBoxSearch";
@@ -60,11 +61,13 @@ export * from "./components/NSCard";
60
61
  export * from "./components/NSCardScreenshot"
61
62
 
62
63
  // Chart
63
- export * from "./components/NSChartColumn";
64
+ export * from "./components/NSChartBar";
65
+ export * from "./components/NSChartLine";
64
66
  export * from "./components/NSChartDoughnut";
65
67
  export * from "./components/NSChartPie";
66
68
  export * from "./components/NSChartRange";
67
- export * from "./components/NSChartTable";
69
+ export * from "./components/NSTableChart";
70
+ export * from "./ColorOperation";
68
71
 
69
72
  // Copy
70
73
  export * from "./components/NSCopyBox";