namirasoft-site-react 1.4.561 → 1.4.562

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 (477) hide show
  1. package/.dockerignore +86 -86
  2. package/.env.template +10 -10
  3. package/Dockerfile +18 -18
  4. package/SKILL.md +307 -307
  5. package/config-overrides.js +72 -72
  6. package/dist/App.css +34 -0
  7. package/dist/App.d.ts +1 -1
  8. package/dist/NSBoxBuilder.d.ts +25 -25
  9. package/dist/components/NSBanner.d.ts +1 -1
  10. package/dist/components/NSBanner.module.css +47 -47
  11. package/dist/components/NSBarAction.d.ts +1 -1
  12. package/dist/components/NSBarAction.module.css +91 -91
  13. package/dist/components/NSBarAlert.d.ts +1 -1
  14. package/dist/components/NSBarAlert.module.css +79 -79
  15. package/dist/components/NSBarNotification.d.ts +1 -1
  16. package/dist/components/NSBarNotification.module.css +34 -34
  17. package/dist/components/NSBarTitle.d.ts +1 -1
  18. package/dist/components/NSBarTitle.module.css +9 -9
  19. package/dist/components/NSBox.module.css +87 -87
  20. package/dist/components/NSBoxBaseCombo.d.ts +2 -1
  21. package/dist/components/NSBoxBaseCombo.js +5 -0
  22. package/dist/components/NSBoxBaseCombo.js.map +1 -1
  23. package/dist/components/NSBoxBaseCombo.module.css +6 -6
  24. package/dist/components/NSBoxBaseLayout.d.ts +1 -1
  25. package/dist/components/NSBoxBaseLayoutRecursive.d.ts +1 -1
  26. package/dist/components/NSBoxBoolean.d.ts +1 -1
  27. package/dist/components/NSBoxBoolean.module.css +73 -73
  28. package/dist/components/NSBoxBooleans.d.ts +1 -1
  29. package/dist/components/NSBoxColor.d.ts +1 -1
  30. package/dist/components/NSBoxCombo.d.ts +1 -1
  31. package/dist/components/NSBoxDate.d.ts +1 -1
  32. package/dist/components/NSBoxDate.module.css +4 -4
  33. package/dist/components/NSBoxDateRange.d.ts +1 -1
  34. package/dist/components/NSBoxDateRangeBase.d.ts +1 -1
  35. package/dist/components/NSBoxDateRangeBase.module.css +73 -73
  36. package/dist/components/NSBoxDateTime.d.ts +1 -1
  37. package/dist/components/NSBoxDateTime.module.css +4 -4
  38. package/dist/components/NSBoxDateTimeRange.d.ts +1 -1
  39. package/dist/components/NSBoxDouble.d.ts +1 -1
  40. package/dist/components/NSBoxDuration.d.ts +1 -1
  41. package/dist/components/NSBoxDuration.module.css +4 -4
  42. package/dist/components/NSBoxDynamic.d.ts +1 -1
  43. package/dist/components/NSBoxDynamics.d.ts +1 -1
  44. package/dist/components/NSBoxEmail.d.ts +1 -1
  45. package/dist/components/NSBoxEntity.d.ts +1 -1
  46. package/dist/components/NSBoxEnum.d.ts +1 -1
  47. package/dist/components/NSBoxFile.d.ts +1 -1
  48. package/dist/components/NSBoxFile.module.css +10 -10
  49. package/dist/components/NSBoxFilePath.d.ts +1 -1
  50. package/dist/components/NSBoxFont.d.ts +1 -1
  51. package/dist/components/NSBoxIPV4.d.ts +1 -1
  52. package/dist/components/NSBoxIPV4Range.d.ts +1 -1
  53. package/dist/components/NSBoxIPV6.d.ts +1 -1
  54. package/dist/components/NSBoxIPV6Range.d.ts +1 -1
  55. package/dist/components/NSBoxInteger.d.ts +1 -1
  56. package/dist/components/NSBoxInteger.module.css +16 -16
  57. package/dist/components/NSBoxMoney.d.ts +1 -1
  58. package/dist/components/NSBoxOptions.d.ts +1 -1
  59. package/dist/components/NSBoxOptions.module.css +53 -53
  60. package/dist/components/NSBoxPhone.d.ts +1 -1
  61. package/dist/components/NSBoxPhone.module.css +35 -35
  62. package/dist/components/NSBoxRadio.d.ts +1 -1
  63. package/dist/components/NSBoxRadio.module.css +33 -33
  64. package/dist/components/NSBoxSchemaBase.d.ts +1 -1
  65. package/dist/components/NSBoxSchemaBase.module.css +17 -17
  66. package/dist/components/NSBoxSchemaVariable.d.ts +1 -1
  67. package/dist/components/NSBoxSchemaVariable.module.css +16 -16
  68. package/dist/components/NSBoxSearch.d.ts +1 -1
  69. package/dist/components/NSBoxSensitive.d.ts +1 -1
  70. package/dist/components/NSBoxString.d.ts +1 -1
  71. package/dist/components/NSBoxTextArea.d.ts +1 -1
  72. package/dist/components/NSBoxTextArea.module.css +12 -12
  73. package/dist/components/NSBoxTime.d.ts +1 -1
  74. package/dist/components/NSBoxTime.module.css +4 -4
  75. package/dist/components/NSBoxTimeRange.d.ts +1 -1
  76. package/dist/components/NSBoxTimeZone.d.ts +1 -1
  77. package/dist/components/NSBoxURL.d.ts +1 -1
  78. package/dist/components/NSBoxVersion.d.ts +1 -1
  79. package/dist/components/NSButton.module.css +57 -57
  80. package/dist/components/NSButtonBlue.d.ts +1 -1
  81. package/dist/components/NSButtonBlue.module.css +4 -4
  82. package/dist/components/NSButtonGreen.d.ts +1 -1
  83. package/dist/components/NSButtonGreen.module.css +4 -4
  84. package/dist/components/NSButtonRed.d.ts +1 -1
  85. package/dist/components/NSButtonRed.module.css +4 -4
  86. package/dist/components/NSCard.d.ts +1 -1
  87. package/dist/components/NSCard.module.css +113 -113
  88. package/dist/components/NSCardScreenshot.d.ts +1 -1
  89. package/dist/components/NSCardScreenshot.module.css +41 -41
  90. package/dist/components/NSChartBar.d.ts +1 -1
  91. package/dist/components/NSChartDoughnut.d.ts +1 -1
  92. package/dist/components/NSChartLine.d.ts +1 -1
  93. package/dist/components/NSChartPie.d.ts +1 -1
  94. package/dist/components/NSChartRange.d.ts +1 -1
  95. package/dist/components/NSColumn.d.ts +1 -1
  96. package/dist/components/NSColumn.module.css +16 -16
  97. package/dist/components/NSCopy.d.ts +1 -1
  98. package/dist/components/NSCopyBox.d.ts +1 -1
  99. package/dist/components/NSCopyBox.module.css +39 -39
  100. package/dist/components/NSDialog.d.ts +1 -1
  101. package/dist/components/NSDialog.module.css +105 -105
  102. package/dist/components/NSDialogBox.d.ts +1 -1
  103. package/dist/components/NSDialogBoxDate.d.ts +1 -1
  104. package/dist/components/NSDialogBoxDateTime.d.ts +1 -1
  105. package/dist/components/NSDialogBoxPhone.d.ts +1 -1
  106. package/dist/components/NSDialogBoxString.d.ts +1 -1
  107. package/dist/components/NSDialogDelete.d.ts +1 -1
  108. package/dist/components/NSDialogInfo.d.ts +1 -1
  109. package/dist/components/NSDialogPageSelection.d.ts +2 -2
  110. package/dist/components/NSDialogPageSelection.module.css +103 -103
  111. package/dist/components/NSDownTimer.d.ts +1 -1
  112. package/dist/components/NSDownTimer.module.css +55 -55
  113. package/dist/components/NSDownload.d.ts +1 -1
  114. package/dist/components/NSDownload.module.css +46 -46
  115. package/dist/components/NSElectronicCard.d.ts +1 -1
  116. package/dist/components/NSElectronicCard.module.css +60 -60
  117. package/dist/components/NSEntityCardBackground.d.ts +1 -1
  118. package/dist/components/NSEntityCardBackground.module.css +27 -27
  119. package/dist/components/NSFilterBox.d.ts +2 -2
  120. package/dist/components/NSFilterBox.module.css +27 -27
  121. package/dist/components/NSFilterBoxItems.d.ts +1 -1
  122. package/dist/components/NSFilterBoxItems.module.css +15 -15
  123. package/dist/components/NSFilterItem.d.ts +1 -1
  124. package/dist/components/NSFilterItem.module.css +24 -24
  125. package/dist/components/NSFooter.d.ts +1 -1
  126. package/dist/components/NSFooter.module.css +140 -140
  127. package/dist/components/NSGauge.d.ts +1 -1
  128. package/dist/components/NSGauge.module.css +67 -67
  129. package/dist/components/NSGaugeDate.d.ts +1 -1
  130. package/dist/components/NSGaugeDate.module.css +57 -57
  131. package/dist/components/NSGaugeNumber.d.ts +1 -1
  132. package/dist/components/NSGaugeNumber.module.css +66 -66
  133. package/dist/components/NSHeader.d.ts +1 -1
  134. package/dist/components/NSHeader.module.css +316 -316
  135. package/dist/components/NSHeaderScreenshot.d.ts +1 -1
  136. package/dist/components/NSHeaderScreenshot.module.css +35 -35
  137. package/dist/components/NSID.d.ts +1 -1
  138. package/dist/components/NSInfo.d.ts +1 -1
  139. package/dist/components/NSLabel.d.ts +1 -1
  140. package/dist/components/NSLabel.module.css +25 -25
  141. package/dist/components/NSLabelErrorNotifier.d.ts +1 -1
  142. package/dist/components/NSLabelErrorNotifier.module.css +2 -2
  143. package/dist/components/NSLabelSensitive.d.ts +1 -1
  144. package/dist/components/NSLabelSensitive.module.css +9 -9
  145. package/dist/components/NSLayout.d.ts +1 -1
  146. package/dist/components/NSLayout.module.css +23 -23
  147. package/dist/components/NSLine.d.ts +1 -1
  148. package/dist/components/NSLine.module.css +15 -15
  149. package/dist/components/NSLineText.d.ts +1 -1
  150. package/dist/components/NSLineText.module.css +38 -38
  151. package/dist/components/NSLink.d.ts +1 -1
  152. package/dist/components/NSLink.module.css +36 -36
  153. package/dist/components/NSLinkBlue.d.ts +1 -1
  154. package/dist/components/NSLinkGreen.d.ts +1 -1
  155. package/dist/components/NSLinkRed.d.ts +1 -1
  156. package/dist/components/NSListGrouped.d.ts +1 -1
  157. package/dist/components/NSListGrouped.module.css +69 -69
  158. package/dist/components/NSListProduct.d.ts +1 -1
  159. package/dist/components/NSLoading.d.ts +1 -1
  160. package/dist/components/NSLoading.module.css +10 -10
  161. package/dist/components/NSMegaMenu.d.ts +1 -1
  162. package/dist/components/NSMegaMenu.module.css +133 -133
  163. package/dist/components/NSMenuAction.d.ts +1 -1
  164. package/dist/components/NSMenuAction.module.css +88 -88
  165. package/dist/components/NSMenuButton.d.ts +1 -1
  166. package/dist/components/NSMenuButton.module.css +44 -44
  167. package/dist/components/NSNoData.d.ts +1 -1
  168. package/dist/components/NSNoData.module.css +11 -11
  169. package/dist/components/NSPagination.d.ts +1 -1
  170. package/dist/components/NSPagination.module.css +87 -87
  171. package/dist/components/NSPanel.d.ts +1 -1
  172. package/dist/components/NSPanel.module.css +19 -19
  173. package/dist/components/NSPanelAccordion.d.ts +1 -1
  174. package/dist/components/NSPanelAccordion.module.css +4 -4
  175. package/dist/components/NSProductSearch.d.ts +1 -1
  176. package/dist/components/NSProductSearch.module.css +73 -73
  177. package/dist/components/NSProgressBar.d.ts +1 -1
  178. package/dist/components/NSProgressBar.module.css +38 -38
  179. package/dist/components/NSRange.d.ts +1 -1
  180. package/dist/components/NSRange.module.css +66 -66
  181. package/dist/components/NSRepeater.d.ts +1 -1
  182. package/dist/components/NSRepeaterNSBoxSchemaVariable.d.ts +1 -1
  183. package/dist/components/NSRepeaterNSTag.d.ts +1 -1
  184. package/dist/components/NSRow.d.ts +1 -1
  185. package/dist/components/NSRow.module.css +17 -17
  186. package/dist/components/NSSection.d.ts +1 -1
  187. package/dist/components/NSSection.module.css +4 -4
  188. package/dist/components/NSSectionCards.d.ts +1 -1
  189. package/dist/components/NSSectionCards.module.css +38 -38
  190. package/dist/components/NSSectionTiles.d.ts +1 -1
  191. package/dist/components/NSSectionTiles.module.css +10 -10
  192. package/dist/components/NSSectionTitle.d.ts +1 -1
  193. package/dist/components/NSSpace.d.ts +1 -1
  194. package/dist/components/NSSplitter.d.ts +1 -1
  195. package/dist/components/NSSplitter.module.css +59 -59
  196. package/dist/components/NSTabPage.d.ts +1 -1
  197. package/dist/components/NSTabPage.module.css +59 -59
  198. package/dist/components/NSTable.d.ts +1 -1
  199. package/dist/components/NSTable.module.css +371 -371
  200. package/dist/components/NSTableChart.d.ts +1 -1
  201. package/dist/components/NSTableChart.module.css +119 -119
  202. package/dist/components/NSTag.d.ts +1 -1
  203. package/dist/components/NSTile.d.ts +1 -1
  204. package/dist/components/NSTile.module.css +76 -76
  205. package/dist/components/NSTimelineMonthly.d.ts +1 -1
  206. package/dist/components/NSTimelineMonthly.module.css +71 -71
  207. package/dist/components/NSTitle.d.ts +1 -1
  208. package/dist/components/NSTitle.module.css +15 -15
  209. package/dist/formatter/StringFormatter.d.ts +1 -1
  210. package/dist/index.css +6 -0
  211. package/dist/pages/NSImplementing.d.ts +1 -1
  212. package/dist/pages/NSImplementing.module.css +35 -35
  213. package/dist/pages/NSNotFoundPage.d.ts +1 -1
  214. package/dist/pages/NSNotFoundPage.module.css +18 -18
  215. package/dist/pages/NSUpdating.d.ts +1 -1
  216. package/dist/pages/NSUpdating.module.css +35 -35
  217. package/package.json +86 -86
  218. package/public/index.html +38 -38
  219. package/src/App.css +33 -33
  220. package/src/App.tsx +198 -198
  221. package/src/Color.tsx +10 -10
  222. package/src/ColorOperation.ts +153 -153
  223. package/src/CopyToClipboard.ts +6 -6
  224. package/src/EncryptionOperation.ts +98 -98
  225. package/src/NSBoxBuilder.tsx +922 -922
  226. package/src/ProductCacheService.ts +15 -15
  227. package/src/Validator.ts +199 -199
  228. package/src/components/INSBox.tsx +7 -7
  229. package/src/components/NSBanner.module.css +47 -47
  230. package/src/components/NSBanner.tsx +80 -80
  231. package/src/components/NSBarAction.module.css +91 -91
  232. package/src/components/NSBarAction.tsx +95 -95
  233. package/src/components/NSBarAlert.module.css +79 -79
  234. package/src/components/NSBarAlert.tsx +35 -35
  235. package/src/components/NSBarNotification.module.css +34 -34
  236. package/src/components/NSBarNotification.tsx +86 -86
  237. package/src/components/NSBarTitle.module.css +9 -9
  238. package/src/components/NSBarTitle.tsx +23 -23
  239. package/src/components/NSBox.module.css +87 -87
  240. package/src/components/NSBox.tsx +19 -19
  241. package/src/components/NSBoxBaseCombo.module.css +6 -6
  242. package/src/components/NSBoxBaseCombo.tsx +488 -483
  243. package/src/components/NSBoxBaseLayout.tsx +163 -163
  244. package/src/components/NSBoxBaseLayoutRecursive.tsx +59 -59
  245. package/src/components/NSBoxBoolean.module.css +73 -73
  246. package/src/components/NSBoxBoolean.tsx +152 -152
  247. package/src/components/NSBoxBooleans.tsx +181 -181
  248. package/src/components/NSBoxColor.tsx +107 -107
  249. package/src/components/NSBoxCombo.tsx +95 -95
  250. package/src/components/NSBoxDate.module.css +4 -4
  251. package/src/components/NSBoxDate.tsx +119 -119
  252. package/src/components/NSBoxDateRange.tsx +88 -88
  253. package/src/components/NSBoxDateRangeBase.module.css +73 -73
  254. package/src/components/NSBoxDateRangeBase.tsx +198 -198
  255. package/src/components/NSBoxDateTime.module.css +4 -4
  256. package/src/components/NSBoxDateTime.tsx +116 -116
  257. package/src/components/NSBoxDateTimeRange.tsx +65 -65
  258. package/src/components/NSBoxDouble.tsx +110 -110
  259. package/src/components/NSBoxDuration.module.css +4 -4
  260. package/src/components/NSBoxDuration.tsx +107 -107
  261. package/src/components/NSBoxDynamic.tsx +77 -77
  262. package/src/components/NSBoxDynamics.tsx +68 -68
  263. package/src/components/NSBoxEmail.tsx +117 -117
  264. package/src/components/NSBoxEntity.tsx +181 -181
  265. package/src/components/NSBoxEnum.tsx +113 -113
  266. package/src/components/NSBoxFile.module.css +10 -10
  267. package/src/components/NSBoxFile.tsx +106 -106
  268. package/src/components/NSBoxFilePath.tsx +106 -106
  269. package/src/components/NSBoxFont.tsx +107 -107
  270. package/src/components/NSBoxIPV4.tsx +107 -107
  271. package/src/components/NSBoxIPV4Range.tsx +107 -107
  272. package/src/components/NSBoxIPV6.tsx +104 -104
  273. package/src/components/NSBoxIPV6Range.tsx +107 -107
  274. package/src/components/NSBoxInteger.module.css +16 -16
  275. package/src/components/NSBoxInteger.tsx +126 -126
  276. package/src/components/NSBoxMoney.tsx +115 -115
  277. package/src/components/NSBoxOptions.module.css +53 -53
  278. package/src/components/NSBoxOptions.tsx +182 -182
  279. package/src/components/NSBoxPhone.module.css +35 -35
  280. package/src/components/NSBoxPhone.tsx +120 -120
  281. package/src/components/NSBoxRadio.module.css +33 -33
  282. package/src/components/NSBoxRadio.tsx +104 -104
  283. package/src/components/NSBoxSchemaBase.module.css +17 -17
  284. package/src/components/NSBoxSchemaBase.tsx +562 -562
  285. package/src/components/NSBoxSchemaVariable.module.css +16 -16
  286. package/src/components/NSBoxSchemaVariable.tsx +263 -263
  287. package/src/components/NSBoxSearch.tsx +112 -112
  288. package/src/components/NSBoxSensitive.tsx +133 -133
  289. package/src/components/NSBoxString.tsx +106 -106
  290. package/src/components/NSBoxTextArea.module.css +12 -12
  291. package/src/components/NSBoxTextArea.tsx +136 -136
  292. package/src/components/NSBoxTime.module.css +4 -4
  293. package/src/components/NSBoxTime.tsx +106 -106
  294. package/src/components/NSBoxTimeRange.tsx +220 -220
  295. package/src/components/NSBoxTimeZone.tsx +122 -122
  296. package/src/components/NSBoxURL.tsx +117 -117
  297. package/src/components/NSBoxVersion.tsx +107 -107
  298. package/src/components/NSButton.module.css +57 -57
  299. package/src/components/NSButton.tsx +74 -74
  300. package/src/components/NSButtonBlue.module.css +4 -4
  301. package/src/components/NSButtonBlue.tsx +29 -29
  302. package/src/components/NSButtonGreen.module.css +4 -4
  303. package/src/components/NSButtonGreen.tsx +29 -29
  304. package/src/components/NSButtonRed.module.css +4 -4
  305. package/src/components/NSButtonRed.tsx +29 -29
  306. package/src/components/NSCard.module.css +113 -113
  307. package/src/components/NSCard.tsx +67 -67
  308. package/src/components/NSCardScreenshot.module.css +41 -41
  309. package/src/components/NSCardScreenshot.tsx +31 -31
  310. package/src/components/NSChartBar.tsx +134 -134
  311. package/src/components/NSChartDoughnut.tsx +114 -114
  312. package/src/components/NSChartLine.tsx +110 -110
  313. package/src/components/NSChartPie.tsx +105 -105
  314. package/src/components/NSChartRange.tsx +14 -14
  315. package/src/components/NSColumn.module.css +16 -16
  316. package/src/components/NSColumn.tsx +24 -24
  317. package/src/components/NSCopy.tsx +58 -58
  318. package/src/components/NSCopyBox.module.css +39 -39
  319. package/src/components/NSCopyBox.tsx +53 -53
  320. package/src/components/NSDialog.module.css +105 -105
  321. package/src/components/NSDialog.tsx +72 -72
  322. package/src/components/NSDialogBox.tsx +38 -38
  323. package/src/components/NSDialogBoxDate.tsx +28 -28
  324. package/src/components/NSDialogBoxDateTime.tsx +28 -28
  325. package/src/components/NSDialogBoxPhone.tsx +28 -28
  326. package/src/components/NSDialogBoxString.tsx +28 -28
  327. package/src/components/NSDialogDelete.tsx +36 -36
  328. package/src/components/NSDialogInfo.tsx +49 -49
  329. package/src/components/NSDialogPageSelection.module.css +103 -103
  330. package/src/components/NSDialogPageSelection.tsx +219 -219
  331. package/src/components/NSDownTimer.module.css +55 -55
  332. package/src/components/NSDownTimer.tsx +91 -91
  333. package/src/components/NSDownload.module.css +46 -46
  334. package/src/components/NSDownload.tsx +69 -69
  335. package/src/components/NSElectronicCard.module.css +60 -60
  336. package/src/components/NSElectronicCard.tsx +46 -46
  337. package/src/components/NSEntityCardBackground.module.css +27 -27
  338. package/src/components/NSEntityCardBackground.tsx +36 -36
  339. package/src/components/NSFilterBox.module.css +27 -27
  340. package/src/components/NSFilterBox.tsx +477 -477
  341. package/src/components/NSFilterBoxItems.module.css +15 -15
  342. package/src/components/NSFilterBoxItems.tsx +52 -52
  343. package/src/components/NSFilterItem.module.css +24 -24
  344. package/src/components/NSFilterItem.tsx +27 -27
  345. package/src/components/NSFooter.module.css +140 -140
  346. package/src/components/NSFooter.tsx +321 -321
  347. package/src/components/NSGauge.module.css +67 -67
  348. package/src/components/NSGauge.tsx +52 -52
  349. package/src/components/NSGaugeDate.module.css +57 -57
  350. package/src/components/NSGaugeDate.tsx +125 -125
  351. package/src/components/NSGaugeNumber.module.css +66 -66
  352. package/src/components/NSGaugeNumber.tsx +90 -90
  353. package/src/components/NSHeader.module.css +316 -316
  354. package/src/components/NSHeader.tsx +334 -334
  355. package/src/components/NSHeaderScreenshot.module.css +35 -35
  356. package/src/components/NSHeaderScreenshot.tsx +39 -39
  357. package/src/components/NSID.tsx +159 -159
  358. package/src/components/NSInfo.tsx +50 -50
  359. package/src/components/NSLabel.module.css +25 -25
  360. package/src/components/NSLabel.tsx +47 -47
  361. package/src/components/NSLabelErrorNotifier.module.css +2 -2
  362. package/src/components/NSLabelErrorNotifier.tsx +35 -35
  363. package/src/components/NSLabelSensitive.module.css +9 -9
  364. package/src/components/NSLabelSensitive.tsx +85 -85
  365. package/src/components/NSLayout.module.css +23 -23
  366. package/src/components/NSLayout.tsx +140 -140
  367. package/src/components/NSLine.module.css +15 -15
  368. package/src/components/NSLine.tsx +13 -13
  369. package/src/components/NSLineText.module.css +38 -38
  370. package/src/components/NSLineText.tsx +17 -17
  371. package/src/components/NSLink.module.css +36 -36
  372. package/src/components/NSLink.tsx +26 -26
  373. package/src/components/NSLinkBlue.tsx +22 -22
  374. package/src/components/NSLinkGreen.tsx +13 -13
  375. package/src/components/NSLinkRed.tsx +13 -13
  376. package/src/components/NSListGrouped.module.css +69 -69
  377. package/src/components/NSListGrouped.tsx +106 -106
  378. package/src/components/NSListProduct.tsx +78 -78
  379. package/src/components/NSLoading.module.css +10 -10
  380. package/src/components/NSLoading.tsx +43 -43
  381. package/src/components/NSMegaMenu.module.css +133 -133
  382. package/src/components/NSMegaMenu.tsx +188 -188
  383. package/src/components/NSMenuAction.module.css +88 -88
  384. package/src/components/NSMenuAction.tsx +106 -106
  385. package/src/components/NSMenuButton.module.css +44 -44
  386. package/src/components/NSMenuButton.tsx +197 -197
  387. package/src/components/NSNoData.module.css +11 -11
  388. package/src/components/NSNoData.tsx +24 -24
  389. package/src/components/NSPagination.module.css +87 -87
  390. package/src/components/NSPagination.tsx +183 -183
  391. package/src/components/NSPanel.module.css +19 -19
  392. package/src/components/NSPanel.tsx +24 -24
  393. package/src/components/NSPanelAccordion.module.css +4 -4
  394. package/src/components/NSPanelAccordion.tsx +51 -51
  395. package/src/components/NSProductSearch.module.css +73 -73
  396. package/src/components/NSProductSearch.tsx +193 -193
  397. package/src/components/NSProgressBar.module.css +38 -38
  398. package/src/components/NSProgressBar.tsx +29 -29
  399. package/src/components/NSRange.module.css +66 -66
  400. package/src/components/NSRange.tsx +83 -83
  401. package/src/components/NSRepeater.tsx +328 -328
  402. package/src/components/NSRepeaterNSBoxSchemaVariable.tsx +94 -94
  403. package/src/components/NSRepeaterNSTag.tsx +86 -86
  404. package/src/components/NSRow.module.css +17 -17
  405. package/src/components/NSRow.tsx +24 -24
  406. package/src/components/NSSection.module.css +4 -4
  407. package/src/components/NSSection.tsx +26 -26
  408. package/src/components/NSSectionCards.module.css +38 -38
  409. package/src/components/NSSectionCards.tsx +51 -51
  410. package/src/components/NSSectionTiles.module.css +10 -10
  411. package/src/components/NSSectionTiles.tsx +25 -25
  412. package/src/components/NSSectionTitle.tsx +19 -19
  413. package/src/components/NSSpace.tsx +28 -28
  414. package/src/components/NSSplitter.module.css +59 -59
  415. package/src/components/NSSplitter.tsx +211 -211
  416. package/src/components/NSTabPage.module.css +59 -59
  417. package/src/components/NSTabPage.tsx +122 -122
  418. package/src/components/NSTable.module.css +371 -371
  419. package/src/components/NSTable.tsx +1115 -1115
  420. package/src/components/NSTableChart.module.css +119 -119
  421. package/src/components/NSTableChart.tsx +587 -587
  422. package/src/components/NSTag.tsx +74 -74
  423. package/src/components/NSTile.module.css +76 -76
  424. package/src/components/NSTile.tsx +27 -27
  425. package/src/components/NSTimelineMonthly.module.css +71 -71
  426. package/src/components/NSTimelineMonthly.tsx +44 -44
  427. package/src/components/NSTitle.module.css +15 -15
  428. package/src/components/NSTitle.tsx +19 -19
  429. package/src/formatter/BackColorFormatter.tsx +23 -23
  430. package/src/formatter/BaseColumnFormatter.ts +18 -18
  431. package/src/formatter/BaseURLImageFormatter.tsx +33 -33
  432. package/src/formatter/BooleanFormatter.ts +22 -22
  433. package/src/formatter/BytesFormatter.tsx +15 -15
  434. package/src/formatter/DateFormatter.ts +22 -22
  435. package/src/formatter/DateTimeFormatter.ts +22 -22
  436. package/src/formatter/DurationFormatter.ts +13 -13
  437. package/src/formatter/EmailFormatter.tsx +21 -21
  438. package/src/formatter/EnumFormatter.ts +13 -13
  439. package/src/formatter/FloatFormatter.ts +23 -23
  440. package/src/formatter/ForeColorFormatter.tsx +24 -24
  441. package/src/formatter/IDFormatter.tsx +53 -53
  442. package/src/formatter/IPFormatter.ts +13 -13
  443. package/src/formatter/IntegerFormatter.ts +23 -23
  444. package/src/formatter/JsonFormatter.tsx +58 -58
  445. package/src/formatter/MoneyFormatter.ts +35 -35
  446. package/src/formatter/PercentFormatter.tsx +39 -39
  447. package/src/formatter/PhoneFormatter.tsx +21 -21
  448. package/src/formatter/SensitiveFormatter.tsx +33 -33
  449. package/src/formatter/StringFormatter.tsx +43 -43
  450. package/src/formatter/TimeFormatter.ts +21 -21
  451. package/src/formatter/URLFormatter.tsx +24 -24
  452. package/src/formatter/UnknowFormatter.ts +18 -18
  453. package/src/index.tsx +7 -7
  454. package/src/main.ts +261 -261
  455. package/src/pages/NSImplementing.module.css +35 -35
  456. package/src/pages/NSImplementing.tsx +32 -32
  457. package/src/pages/NSNotFoundPage.module.css +18 -18
  458. package/src/pages/NSNotFoundPage.tsx +14 -14
  459. package/src/pages/NSUpdating.module.css +35 -35
  460. package/src/pages/NSUpdating.tsx +32 -32
  461. package/src/props/IBackgroundProps.ts +5 -5
  462. package/src/props/IBaseComponentProps.ts +8 -8
  463. package/src/props/IHeaderIconProps.ts +10 -10
  464. package/src/props/IHeaderLeftProps.ts +6 -6
  465. package/src/props/IHeaderRightProps.ts +8 -8
  466. package/src/props/IImageProps.ts +4 -4
  467. package/src/props/ILinkProps.ts +4 -4
  468. package/src/props/IValidationNumberProps.ts +4 -4
  469. package/src/props/IValidationPrecisionProps.ts +3 -3
  470. package/src/props/IValidationProps.ts +9 -9
  471. package/src/props/IValidationRegexProps.ts +4 -4
  472. package/src/props/IValidationStringProps.ts +4 -4
  473. package/src/routing/NSNotifier.ts +114 -114
  474. package/src/routing/NSRouterMaker.tsx +20 -20
  475. package/src/routing/NSRouterMakerComponent.ts +5 -5
  476. package/src/routing/NSRouterMakerProps.ts +5 -5
  477. package/tsconfig.json +43 -43
@@ -1,588 +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
- }
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
588
  }