@variocube/app-ui 1.14.5 → 1.16.0

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 (323) hide show
  1. package/esm/AppShell/AppShell.js +12 -12
  2. package/esm/AppShell/AppShell.js.map +1 -1
  3. package/esm/AppShell/index.js.map +1 -1
  4. package/esm/Input/ActionsMenu.js +1 -1
  5. package/esm/Input/ActionsMenu.js.map +1 -1
  6. package/esm/Input/EmailSenderField.js +3 -3
  7. package/esm/Input/EmailSenderField.js.map +1 -1
  8. package/esm/Input/Selector.js +2 -2
  9. package/esm/Input/Selector.js.map +1 -1
  10. package/esm/Paging/Paging.d.ts +1 -1
  11. package/esm/Paging/Paging.js +5 -5
  12. package/esm/Paging/Paging.js.map +1 -1
  13. package/esm/Paging/index.d.ts +2 -1
  14. package/esm/Paging/index.js.map +1 -1
  15. package/esm/VCThemeProvider/JetbrainsMonoFont.js +8 -8
  16. package/esm/VCThemeProvider/JetbrainsMonoFont.js.map +1 -1
  17. package/esm/VCThemeProvider/RobotoFont.js +8 -8
  18. package/esm/VCThemeProvider/RobotoFont.js.map +1 -1
  19. package/esm/VCThemeProvider/ThemeModeSwitcher.js +5 -5
  20. package/esm/VCThemeProvider/ThemeModeSwitcher.js.map +1 -1
  21. package/esm/VCThemeProvider/VCThemeProvider.d.ts +1 -1
  22. package/esm/VCThemeProvider/VCThemeProvider.js +21 -21
  23. package/esm/VCThemeProvider/VCThemeProvider.js.map +1 -1
  24. package/esm/audit/AuditChanges.js +9 -5
  25. package/esm/audit/AuditChanges.js.map +1 -1
  26. package/esm/audit/AuditTimeline.js +1 -1
  27. package/esm/audit/AuditTimeline.js.map +1 -1
  28. package/esm/audit/AuditTimelineItem.js +3 -3
  29. package/esm/audit/AuditTimelineItem.js.map +1 -1
  30. package/esm/audit/index.d.ts +1 -1
  31. package/esm/audit/index.js +1 -1
  32. package/esm/audit/index.js.map +1 -1
  33. package/esm/breadcrumbs.d.ts +2 -2
  34. package/esm/breadcrumbs.js +3 -3
  35. package/esm/breadcrumbs.js.map +1 -1
  36. package/esm/code/CodeBlock.d.ts +1 -1
  37. package/esm/code/CodeBlock.js +1 -1
  38. package/esm/code/CodeBlock.js.map +1 -1
  39. package/esm/confirm/ConfirmButton.js.map +1 -1
  40. package/esm/confirm/ConfirmDialog.js +1 -1
  41. package/esm/confirm/ConfirmDialog.js.map +1 -1
  42. package/esm/confirm/ConfirmMenuItem.js +1 -1
  43. package/esm/confirm/ConfirmMenuItem.js.map +1 -1
  44. package/esm/container/ContainerLayout.d.ts +1 -1
  45. package/esm/container/ContainerLayout.js +5 -5
  46. package/esm/container/ContainerLayout.js.map +1 -1
  47. package/esm/container/ContainerSettingsContext.d.ts +2 -2
  48. package/esm/container/ContainerSettingsContext.js +6 -6
  49. package/esm/container/ContainerSettingsContext.js.map +1 -1
  50. package/esm/container/ContainerWidthControl.js +2 -2
  51. package/esm/container/ContainerWidthControl.js.map +1 -1
  52. package/esm/container/index.d.ts +1 -1
  53. package/esm/container/index.js +1 -1
  54. package/esm/container/index.js.map +1 -1
  55. package/esm/content-table/ContentTable.d.ts +1 -1
  56. package/esm/content-table/ContentTable.js +26 -19
  57. package/esm/content-table/ContentTable.js.map +1 -1
  58. package/esm/content-table/UndrawEmpty.js.map +1 -1
  59. package/esm/content-table/index.js.map +1 -1
  60. package/esm/country/country-select.js.map +1 -1
  61. package/esm/country/index.d.ts +3 -3
  62. package/esm/country/index.js +3 -3
  63. package/esm/country/index.js.map +1 -1
  64. package/esm/country/locale-select.js +1 -1
  65. package/esm/country/locale-select.js.map +1 -1
  66. package/esm/country/locales.js +1 -1
  67. package/esm/country/locales.js.map +1 -1
  68. package/esm/country/phone-prefix-select.js +1 -1
  69. package/esm/country/phone-prefix-select.js.map +1 -1
  70. package/esm/cube/accessibility.js +2 -1
  71. package/esm/cube/accessibility.js.map +1 -1
  72. package/esm/data-table/DataTableColumnSettings.d.ts +1 -1
  73. package/esm/data-table/DataTableColumnSettings.js +2 -2
  74. package/esm/data-table/DataTableColumnSettings.js.map +1 -1
  75. package/esm/data-table/DataTableHeader.js +1 -1
  76. package/esm/data-table/DataTableHeader.js.map +1 -1
  77. package/esm/data-table/DataTableToolbar.js +1 -1
  78. package/esm/data-table/DataTableToolbar.js.map +1 -1
  79. package/esm/data-table/index.d.ts +4 -4
  80. package/esm/data-table/index.js +4 -4
  81. package/esm/data-table/index.js.map +1 -1
  82. package/esm/data-table/useDataTableColumnStorage.d.ts +9 -1
  83. package/esm/data-table/useDataTableColumnStorage.js +12 -5
  84. package/esm/data-table/useDataTableColumnStorage.js.map +1 -1
  85. package/esm/data-table/useDataTableStorage.d.ts +31 -6
  86. package/esm/data-table/useDataTableStorage.js +25 -5
  87. package/esm/data-table/useDataTableStorage.js.map +1 -1
  88. package/esm/date-pickers/PlainAdapterCommon.d.ts +1 -1
  89. package/esm/date-pickers/PlainAdapterCommon.js.map +1 -1
  90. package/esm/date-pickers/PlainDateAdapter.js.map +1 -1
  91. package/esm/date-pickers/PlainDatePicker.js +1 -1
  92. package/esm/date-pickers/PlainDatePicker.js.map +1 -1
  93. package/esm/date-pickers/PlainDatePicker.spec.js +2 -2
  94. package/esm/date-pickers/PlainDatePicker.spec.js.map +1 -1
  95. package/esm/date-pickers/PlainDateTimeAdapter.js.map +1 -1
  96. package/esm/date-pickers/PlainDateTimePicker.js +2 -2
  97. package/esm/date-pickers/PlainDateTimePicker.js.map +1 -1
  98. package/esm/date-pickers/PlainDateTimePicker.spec.js +2 -2
  99. package/esm/date-pickers/PlainDateTimePicker.spec.js.map +1 -1
  100. package/esm/date-pickers/PlainTimeAdapter.js.map +1 -1
  101. package/esm/date-pickers/PlainTimePicker.js +2 -2
  102. package/esm/date-pickers/PlainTimePicker.js.map +1 -1
  103. package/esm/date-pickers/PlainTimePicker.spec.js +2 -2
  104. package/esm/date-pickers/PlainTimePicker.spec.js.map +1 -1
  105. package/esm/date-pickers/TemporalAdapter.d.ts +1 -1
  106. package/esm/date-pickers/TemporalAdapter.js +1 -1
  107. package/esm/date-pickers/TemporalAdapter.js.map +1 -1
  108. package/esm/date-pickers/TimezoneSelect.js +348 -348
  109. package/esm/date-pickers/TimezoneSelect.js.map +1 -1
  110. package/esm/date-pickers/getFormatString.js.map +1 -1
  111. package/esm/date-pickers/index.d.ts +2 -1
  112. package/esm/date-pickers/index.js +1 -1
  113. package/esm/date-pickers/index.js.map +1 -1
  114. package/esm/date-pickers/parse.js.map +1 -1
  115. package/esm/date-pickers/timeframe-picker.js +7 -7
  116. package/esm/date-pickers/timeframe-picker.js.map +1 -1
  117. package/esm/date-pickers/useLocale.js.map +1 -1
  118. package/esm/date-pickers/useRenderInput.js +5 -3
  119. package/esm/date-pickers/useRenderInput.js.map +1 -1
  120. package/esm/fetch.d.ts +2 -3
  121. package/esm/fetch.js +4 -4
  122. package/esm/fetch.js.map +1 -1
  123. package/esm/formats/CompactFormat.js +1 -1
  124. package/esm/formats/CompactFormat.js.map +1 -1
  125. package/esm/formats/CompactFormat.spec.js +1 -1
  126. package/esm/formats/CompactFormat.spec.js.map +1 -1
  127. package/esm/formats/CurrencyFormat.js +1 -1
  128. package/esm/formats/CurrencyFormat.js.map +1 -1
  129. package/esm/formats/CurrencyFormat.spec.js +1 -1
  130. package/esm/formats/CurrencyFormat.spec.js.map +1 -1
  131. package/esm/formats/DecimalFormat.js +1 -1
  132. package/esm/formats/DecimalFormat.js.map +1 -1
  133. package/esm/formats/DecimalFormat.spec.js +1 -1
  134. package/esm/formats/DecimalFormat.spec.js.map +1 -1
  135. package/esm/formats/DurationFormat.js +2 -2
  136. package/esm/formats/DurationFormat.js.map +1 -1
  137. package/esm/formats/DurationFormat.spec.js +2 -2
  138. package/esm/formats/DurationFormat.spec.js.map +1 -1
  139. package/esm/formats/TemporalFormat.spec.js +2 -2
  140. package/esm/formats/TemporalFormat.spec.js.map +1 -1
  141. package/esm/formats/TemporalRangeFormat.js +1 -1
  142. package/esm/formats/TemporalRangeFormat.js.map +1 -1
  143. package/esm/formats/TemporalRangeFormat.spec.js +2 -2
  144. package/esm/formats/TemporalRangeFormat.spec.js.map +1 -1
  145. package/esm/formats/useDateTimeFormat.js +5 -2
  146. package/esm/formats/useDateTimeFormat.js.map +1 -1
  147. package/esm/formats/useNumberFormat.js +1 -1
  148. package/esm/formats/useNumberFormat.js.map +1 -1
  149. package/esm/formats/useRelativeTimeFormat.js +4 -2
  150. package/esm/formats/useRelativeTimeFormat.js.map +1 -1
  151. package/esm/forms/SearchForm.js +1 -1
  152. package/esm/forms/SearchForm.js.map +1 -1
  153. package/esm/getNavigatorLanguages.js.map +1 -1
  154. package/esm/getSupportedFormatLocale.js.map +1 -1
  155. package/esm/help/HelpDrawer.js +12 -8
  156. package/esm/help/HelpDrawer.js.map +1 -1
  157. package/esm/help/index.d.ts +1 -1
  158. package/esm/help/index.js +1 -1
  159. package/esm/help/index.js.map +1 -1
  160. package/esm/icons.d.ts +13 -13
  161. package/esm/icons.js +13 -13
  162. package/esm/icons.js.map +1 -1
  163. package/esm/layout/ErrorBoundary.js +36 -36
  164. package/esm/layout/ErrorBoundary.js.map +1 -1
  165. package/esm/layout/NotFound.js +6 -6
  166. package/esm/layout/NotFound.js.map +1 -1
  167. package/esm/layout/NotFoundSvg.js.map +1 -1
  168. package/esm/layout/UserNav.js +18 -18
  169. package/esm/layout/UserNav.js.map +1 -1
  170. package/esm/layout/index.d.ts +2 -2
  171. package/esm/layout/index.js +2 -2
  172. package/esm/layout/index.js.map +1 -1
  173. package/esm/logo/Logo.js +2 -2
  174. package/esm/logo/Logo.js.map +1 -1
  175. package/esm/logo/VCAppLogo.js +1 -1
  176. package/esm/logo/VCAppLogo.js.map +1 -1
  177. package/esm/logo/index.d.ts +3 -3
  178. package/esm/logo/index.js +3 -3
  179. package/esm/logo/index.js.map +1 -1
  180. package/esm/splash/index.js +2 -2
  181. package/esm/splash/index.js.map +1 -1
  182. package/esm/storage/MemoryStorage.d.ts +6 -4
  183. package/esm/storage/MemoryStorage.js +13 -4
  184. package/esm/storage/MemoryStorage.js.map +1 -1
  185. package/esm/storage/index.d.ts +2 -1
  186. package/esm/storage/index.js +1 -1
  187. package/esm/storage/index.js.map +1 -1
  188. package/esm/storage/storage.d.ts +6 -4
  189. package/esm/storage/storage.js +35 -15
  190. package/esm/storage/storage.js.map +1 -1
  191. package/esm/storage/types.d.ts +6 -0
  192. package/esm/storage/types.js +2 -0
  193. package/esm/storage/types.js.map +1 -0
  194. package/esm/storage/useStorage.d.ts +10 -1
  195. package/esm/storage/useStorage.js +18 -6
  196. package/esm/storage/useStorage.js.map +1 -1
  197. package/esm/tabs/Tabs.d.ts +2 -2
  198. package/esm/tabs/Tabs.js +15 -15
  199. package/esm/tabs/Tabs.js.map +1 -1
  200. package/esm/tabs/index.js.map +1 -1
  201. package/esm/temporal/index.d.ts +1 -1
  202. package/esm/temporal/index.js +1 -1
  203. package/esm/temporal/index.js.map +1 -1
  204. package/esm/temporal/parse.js.map +1 -1
  205. package/esm/temporal/polyfill.d.ts +1 -1
  206. package/esm/temporal/polyfill.js +3 -3
  207. package/esm/temporal/polyfill.js.map +1 -1
  208. package/esm/utils/defined.js.map +1 -1
  209. package/esm/utils/index.d.ts +1 -1
  210. package/esm/utils/index.js +1 -1
  211. package/esm/utils/index.js.map +1 -1
  212. package/esm/utils/useFlag.js.map +1 -1
  213. package/esm/utils/useIsMounted.js.map +1 -1
  214. package/package.json +8 -9
  215. package/src/AppShell/AppShell.tsx +147 -140
  216. package/src/AppShell/index.tsx +1 -1
  217. package/src/Input/ActionsMenu.tsx +70 -73
  218. package/src/Input/EmailSenderField.tsx +59 -52
  219. package/src/Input/Selector.tsx +15 -15
  220. package/src/LanguageSwitcher/index.ts +1 -1
  221. package/src/Paging/Paging.ts +56 -57
  222. package/src/Paging/index.ts +2 -1
  223. package/src/VCThemeProvider/JetbrainsMonoFont.tsx +52 -42
  224. package/src/VCThemeProvider/RobotoFont.tsx +47 -39
  225. package/src/VCThemeProvider/ThemeModeSwitcher.tsx +17 -17
  226. package/src/VCThemeProvider/VCThemeProvider.tsx +149 -145
  227. package/src/audit/AuditChanges.tsx +18 -12
  228. package/src/audit/AuditTimeline.tsx +16 -17
  229. package/src/audit/AuditTimelineItem.tsx +58 -61
  230. package/src/audit/index.ts +2 -2
  231. package/src/audit/types.ts +27 -28
  232. package/src/breadcrumbs.tsx +11 -15
  233. package/src/code/CodeBlock.tsx +10 -10
  234. package/src/confirm/ConfirmButton.tsx +56 -56
  235. package/src/confirm/ConfirmDialog.tsx +54 -54
  236. package/src/confirm/ConfirmMenuItem.tsx +51 -53
  237. package/src/container/ContainerLayout.tsx +7 -8
  238. package/src/container/ContainerSettingsContext.tsx +49 -46
  239. package/src/container/ContainerWidthControl.tsx +11 -9
  240. package/src/container/index.ts +8 -3
  241. package/src/content-table/ContentTable.tsx +235 -197
  242. package/src/content-table/UndrawEmpty.tsx +281 -281
  243. package/src/content-table/index.ts +1 -1
  244. package/src/country/country-select.tsx +0 -1
  245. package/src/country/index.ts +3 -3
  246. package/src/country/locale-select.tsx +36 -36
  247. package/src/country/locales.ts +185 -187
  248. package/src/country/phone-prefix-select.tsx +4 -5
  249. package/src/cube/accessibility.tsx +2 -1
  250. package/src/data-table/DataTableColumnSettings.tsx +181 -181
  251. package/src/data-table/DataTableHeader.tsx +6 -6
  252. package/src/data-table/DataTableToolbar.tsx +6 -6
  253. package/src/data-table/index.tsx +4 -4
  254. package/src/data-table/useDataTableColumnStorage.ts +30 -19
  255. package/src/data-table/useDataTableStorage.spec.ts +108 -0
  256. package/src/data-table/useDataTableStorage.ts +91 -36
  257. package/src/date-pickers/PlainAdapterCommon.ts +118 -120
  258. package/src/date-pickers/PlainDateAdapter.spec.ts +44 -46
  259. package/src/date-pickers/PlainDateAdapter.ts +130 -132
  260. package/src/date-pickers/PlainDatePicker.spec.tsx +17 -18
  261. package/src/date-pickers/PlainDatePicker.tsx +33 -36
  262. package/src/date-pickers/PlainDateTimeAdapter.spec.ts +44 -46
  263. package/src/date-pickers/PlainDateTimeAdapter.ts +141 -134
  264. package/src/date-pickers/PlainDateTimePicker.spec.tsx +17 -18
  265. package/src/date-pickers/PlainDateTimePicker.tsx +35 -36
  266. package/src/date-pickers/PlainTimeAdapter.ts +219 -221
  267. package/src/date-pickers/PlainTimePicker.spec.tsx +17 -18
  268. package/src/date-pickers/PlainTimePicker.tsx +35 -34
  269. package/src/date-pickers/TemporalAdapter.ts +110 -111
  270. package/src/date-pickers/TimezoneSelect.tsx +375 -375
  271. package/src/date-pickers/getFormatString.ts +29 -29
  272. package/src/date-pickers/index.ts +6 -5
  273. package/src/date-pickers/parse.spec.ts +37 -40
  274. package/src/date-pickers/parse.ts +44 -47
  275. package/src/date-pickers/timeframe-picker.tsx +16 -17
  276. package/src/date-pickers/useLocale.ts +1 -1
  277. package/src/date-pickers/useRenderInput.tsx +24 -15
  278. package/src/fetch.ts +4 -5
  279. package/src/formats/CompactFormat.spec.tsx +18 -20
  280. package/src/formats/CompactFormat.tsx +30 -30
  281. package/src/formats/CurrencyFormat.spec.tsx +18 -20
  282. package/src/formats/CurrencyFormat.tsx +52 -52
  283. package/src/formats/DecimalFormat.spec.tsx +18 -20
  284. package/src/formats/DecimalFormat.tsx +47 -47
  285. package/src/formats/DurationFormat.spec.tsx +48 -49
  286. package/src/formats/DurationFormat.tsx +51 -51
  287. package/src/formats/TemporalFormat.spec.tsx +93 -95
  288. package/src/formats/TemporalRangeFormat.spec.tsx +143 -144
  289. package/src/formats/TemporalRangeFormat.tsx +54 -54
  290. package/src/formats/types.ts +1 -3
  291. package/src/formats/useDateTimeFormat.ts +5 -2
  292. package/src/formats/useNumberFormat.ts +3 -3
  293. package/src/formats/useRelativeTimeFormat.ts +5 -3
  294. package/src/forms/SearchForm.tsx +37 -38
  295. package/src/getNavigatorLanguages.ts +4 -5
  296. package/src/getSupportedFormatLocale.ts +10 -10
  297. package/src/help/HelpDrawer.tsx +76 -55
  298. package/src/help/index.ts +3 -3
  299. package/src/icons.ts +21 -21
  300. package/src/layout/ErrorBoundary.tsx +226 -215
  301. package/src/layout/NotFound.tsx +36 -39
  302. package/src/layout/NotFoundSvg.tsx +193 -169
  303. package/src/layout/UserNav.tsx +98 -98
  304. package/src/layout/index.ts +3 -3
  305. package/src/logo/Logo.tsx +6 -7
  306. package/src/logo/VCAppLogo.tsx +22 -20
  307. package/src/logo/index.tsx +3 -3
  308. package/src/splash/index.tsx +25 -25
  309. package/src/storage/MemoryStorage.ts +22 -15
  310. package/src/storage/index.ts +2 -1
  311. package/src/storage/storage.spec.ts +184 -0
  312. package/src/storage/storage.ts +37 -15
  313. package/src/storage/types.ts +6 -0
  314. package/src/storage/useStorage.ts +21 -6
  315. package/src/tabs/Tabs.tsx +172 -170
  316. package/src/tabs/index.ts +1 -1
  317. package/src/temporal/index.ts +1 -1
  318. package/src/temporal/parse.ts +1 -2
  319. package/src/temporal/polyfill.ts +11 -11
  320. package/src/utils/defined.ts +2 -3
  321. package/src/utils/index.ts +1 -1
  322. package/src/utils/useFlag.ts +5 -5
  323. package/src/utils/useIsMounted.ts +9 -9
@@ -1,28 +1,30 @@
1
1
  import {Box, BoxProps} from "@mui/material";
2
- import {VCLogoIcon} from "./VCLogoIcon";
3
2
  import React from "react";
3
+ import {VCLogoIcon} from "./VCLogoIcon";
4
4
 
5
5
  interface VCAppLogoProps extends BoxProps {
6
- appName?: string;
6
+ appName?: string;
7
7
  }
8
8
 
9
9
  export function VCAppLogo({appName, ...props}: VCAppLogoProps) {
10
- return (
11
- <Box {...props}>
12
- <Box sx={{display: "flex", flexFlow: "row nowrap", alignItems: "center"}}>
13
- <VCLogoIcon width="auto" height="32" display="block"/>
14
- {appName && (
15
- <Box sx={{
16
- lineHeight: 1,
17
- fontSize: "20px",
18
- fontWeight: 900,
19
- textTransform: "uppercase",
20
- marginLeft: "8px",
21
- }}>
22
- {appName}
23
- </Box>
24
- )}
25
- </Box>
26
- </Box>
27
- )
10
+ return (
11
+ <Box {...props}>
12
+ <Box sx={{display: "flex", flexFlow: "row nowrap", alignItems: "center"}}>
13
+ <VCLogoIcon width="auto" height="32" display="block" />
14
+ {appName && (
15
+ <Box
16
+ sx={{
17
+ lineHeight: 1,
18
+ fontSize: "20px",
19
+ fontWeight: 900,
20
+ textTransform: "uppercase",
21
+ marginLeft: "8px",
22
+ }}
23
+ >
24
+ {appName}
25
+ </Box>
26
+ )}
27
+ </Box>
28
+ </Box>
29
+ );
28
30
  }
@@ -1,4 +1,4 @@
1
- export * from "./VCLogoIcon";
2
- export * from "./VCLogo";
3
- export * from "./VCAppLogo";
4
1
  export * from "./Logo";
2
+ export * from "./VCAppLogo";
3
+ export * from "./VCLogo";
4
+ export * from "./VCLogoIcon";
@@ -2,33 +2,33 @@ import React, {FunctionComponentElement} from "react";
2
2
  import ReactDOM from "react-dom";
3
3
 
4
4
  export function render(element: FunctionComponentElement<any> | Array<FunctionComponentElement<any>>) {
5
- try {
6
- ReactDOM.render(element, document.querySelector("#react-root"), removeSplash);
7
- }
8
- catch (error) {
9
- // show the error using the class defined in the template
10
- // this can obviously be improved
11
- ReactDOM.render((
12
- <div className="splash-error">
13
- <h1>Failed to load application</h1>
14
- <p>
15
- An error occurred while loading the application.
16
- Please make sure you are using a current browser version.
17
- </p>
18
- </div>
19
- ), document.body);
20
- }
5
+ try {
6
+ ReactDOM.render(element, document.querySelector("#react-root"), removeSplash);
7
+ } catch (error) {
8
+ // show the error using the class defined in the template
9
+ // this can obviously be improved
10
+ ReactDOM.render(
11
+ <div className="splash-error">
12
+ <h1>Failed to load application</h1>
13
+ <p>
14
+ An error occurred while loading the application. Please make sure you are using a current browser
15
+ version.
16
+ </p>
17
+ </div>,
18
+ document.body,
19
+ );
20
+ }
21
21
  }
22
22
 
23
23
  export async function removeSplash() {
24
- // wait for fonts to become ready
25
- if (document.fonts) {
26
- await document.fonts.ready;
27
- }
24
+ // wait for fonts to become ready
25
+ if (document.fonts) {
26
+ await document.fonts.ready;
27
+ }
28
28
 
29
- const preloader = document.querySelector("#splash");
30
- if (preloader) {
31
- preloader.classList.add("fadeout");
32
- setTimeout(() => preloader.parentNode?.removeChild(preloader), 500);
33
- }
29
+ const preloader = document.querySelector("#splash");
30
+ if (preloader) {
31
+ preloader.classList.add("fadeout");
32
+ setTimeout(() => preloader.parentNode?.removeChild(preloader), 500);
33
+ }
34
34
  }
@@ -1,21 +1,28 @@
1
+ export class MemoryStorage implements Storage {
2
+ private readonly data = new Map<string, string>();
1
3
 
2
- export class MemoryStorage {
4
+ get length(): number {
5
+ return this.data.size;
6
+ }
3
7
 
4
- private readonly data = new Map<string, string>();
8
+ key(index: number): string | null {
9
+ const keys = Array.from(this.data.keys());
10
+ return keys[index] ?? null;
11
+ }
5
12
 
6
- getItem(key: string) {
7
- return this.data.get(key);
8
- }
13
+ getItem(key: string): string | null {
14
+ return this.data.get(key) ?? null;
15
+ }
9
16
 
10
- setItem(key: string, value: string) {
11
- return this.data.set(key, value);
12
- }
17
+ setItem(key: string, value: string): void {
18
+ this.data.set(key, value);
19
+ }
13
20
 
14
- removeItem(key: string) {
15
- return this.data.delete(key);
16
- }
21
+ removeItem(key: string): void {
22
+ this.data.delete(key);
23
+ }
17
24
 
18
- clear() {
19
- return this.data.clear();
20
- }
21
- }
25
+ clear(): void {
26
+ this.data.clear();
27
+ }
28
+ }
@@ -1,2 +1,3 @@
1
- export * from "./useStorage";
2
1
  export * from "./storage";
2
+ export type { StorageType } from "./types";
3
+ export * from "./useStorage";
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+
5
+ import {storage} from "./storage";
6
+
7
+ describe("StorageWrapper", () => {
8
+ beforeEach(() => {
9
+ localStorage.clear();
10
+ sessionStorage.clear();
11
+ });
12
+
13
+ describe("read/write with storage type", () => {
14
+ test("writes to localStorage by default", () => {
15
+ storage.write("test-key", "value");
16
+ expect(localStorage.getItem("test-key")).toBe("value");
17
+ expect(sessionStorage.getItem("test-key")).toBeNull();
18
+ });
19
+
20
+ test("writes to localStorage when explicitly specified", () => {
21
+ storage.write("test-key", "value", "local");
22
+ expect(localStorage.getItem("test-key")).toBe("value");
23
+ expect(sessionStorage.getItem("test-key")).toBeNull();
24
+ });
25
+
26
+ test("writes to sessionStorage when specified", () => {
27
+ storage.write("test-key", "value", "session");
28
+ expect(sessionStorage.getItem("test-key")).toBe("value");
29
+ expect(localStorage.getItem("test-key")).toBeNull();
30
+ });
31
+
32
+ test("reads from correct storage area by default (local)", () => {
33
+ localStorage.setItem("key1", "local-value");
34
+ sessionStorage.setItem("key1", "session-value");
35
+
36
+ expect(storage.read("key1")).toBe("local-value");
37
+ });
38
+
39
+ test("reads from localStorage when explicitly specified", () => {
40
+ localStorage.setItem("key1", "local-value");
41
+ sessionStorage.setItem("key1", "session-value");
42
+
43
+ expect(storage.read("key1", "local")).toBe("local-value");
44
+ });
45
+
46
+ test("reads from sessionStorage when specified", () => {
47
+ localStorage.setItem("key1", "local-value");
48
+ sessionStorage.setItem("key1", "session-value");
49
+
50
+ expect(storage.read("key1", "session")).toBe("session-value");
51
+ });
52
+
53
+ test("returns null for non-existent keys", () => {
54
+ expect(storage.read("non-existent")).toBeNull();
55
+ expect(storage.read("non-existent", "local")).toBeNull();
56
+ expect(storage.read("non-existent", "session")).toBeNull();
57
+ });
58
+ });
59
+
60
+ describe("delete with storage type", () => {
61
+ test("deletes from localStorage by default", () => {
62
+ localStorage.setItem("key", "local");
63
+ sessionStorage.setItem("key", "session");
64
+
65
+ storage.delete("key");
66
+ expect(localStorage.getItem("key")).toBeNull();
67
+ expect(sessionStorage.getItem("key")).toBe("session");
68
+ });
69
+
70
+ test("deletes from localStorage when explicitly specified", () => {
71
+ localStorage.setItem("key", "local");
72
+ sessionStorage.setItem("key", "session");
73
+
74
+ storage.delete("key", "local");
75
+ expect(localStorage.getItem("key")).toBeNull();
76
+ expect(sessionStorage.getItem("key")).toBe("session");
77
+ });
78
+
79
+ test("deletes from sessionStorage when specified", () => {
80
+ localStorage.setItem("key", "local");
81
+ sessionStorage.setItem("key", "session");
82
+
83
+ storage.delete("key", "session");
84
+ expect(localStorage.getItem("key")).toBe("local");
85
+ expect(sessionStorage.getItem("key")).toBeNull();
86
+ });
87
+ });
88
+
89
+ describe("storage isolation", () => {
90
+ test("local and session storage are isolated", () => {
91
+ storage.write("shared-key", "local-value", "local");
92
+ storage.write("shared-key", "session-value", "session");
93
+
94
+ expect(storage.read("shared-key", "local")).toBe("local-value");
95
+ expect(storage.read("shared-key", "session")).toBe("session-value");
96
+ });
97
+
98
+ test("deleting from one storage does not affect the other", () => {
99
+ storage.write("shared-key", "local-value", "local");
100
+ storage.write("shared-key", "session-value", "session");
101
+
102
+ storage.delete("shared-key", "local");
103
+
104
+ expect(storage.read("shared-key", "local")).toBeNull();
105
+ expect(storage.read("shared-key", "session")).toBe("session-value");
106
+ });
107
+ });
108
+
109
+ describe("write with undefined value removes key", () => {
110
+ test("removes key when writing undefined to localStorage", () => {
111
+ storage.write("key", "value", "local");
112
+ expect(storage.read("key", "local")).toBe("value");
113
+
114
+ storage.write("key", undefined, "local");
115
+ expect(storage.read("key", "local")).toBeNull();
116
+ });
117
+
118
+ test("removes key when writing undefined to sessionStorage", () => {
119
+ storage.write("key", "value", "session");
120
+ expect(storage.read("key", "session")).toBe("value");
121
+
122
+ storage.write("key", undefined, "session");
123
+ expect(storage.read("key", "session")).toBeNull();
124
+ });
125
+ });
126
+
127
+ describe("change listeners", () => {
128
+ test("notifies listeners on write", () => {
129
+ const listener = jest.fn();
130
+ storage.addChangeListener("key", listener);
131
+
132
+ storage.write("key", "value");
133
+ expect(listener).toHaveBeenCalledWith(null, "value");
134
+
135
+ storage.removeChangeListener("key", listener);
136
+ });
137
+
138
+ test("notifies listeners on delete", () => {
139
+ storage.write("key", "value");
140
+
141
+ const listener = jest.fn();
142
+ storage.addChangeListener("key", listener);
143
+
144
+ storage.delete("key");
145
+ expect(listener).toHaveBeenCalledWith("value", undefined);
146
+
147
+ storage.removeChangeListener("key", listener);
148
+ });
149
+
150
+ test("notifies listeners on update", () => {
151
+ storage.write("key", "old-value");
152
+
153
+ const listener = jest.fn();
154
+ storage.addChangeListener("key", listener);
155
+
156
+ storage.write("key", "new-value");
157
+ expect(listener).toHaveBeenCalledWith("old-value", "new-value");
158
+
159
+ storage.removeChangeListener("key", listener);
160
+ });
161
+
162
+ test("does not notify after listener removal", () => {
163
+ const listener = jest.fn();
164
+ storage.addChangeListener("key", listener);
165
+ storage.removeChangeListener("key", listener);
166
+
167
+ storage.write("key", "value");
168
+ expect(listener).not.toHaveBeenCalled();
169
+ });
170
+
171
+ test("notifies listeners for different storage types", () => {
172
+ const listener = jest.fn();
173
+ storage.addChangeListener("key", listener);
174
+
175
+ storage.write("key", "local-value", "local");
176
+ expect(listener).toHaveBeenCalledWith(null, "local-value");
177
+
178
+ storage.write("key", "session-value", "session");
179
+ expect(listener).toHaveBeenCalledWith(null, "session-value");
180
+
181
+ storage.removeChangeListener("key", listener);
182
+ });
183
+ });
184
+ });
@@ -1,4 +1,5 @@
1
1
  import {MemoryStorage} from "./MemoryStorage";
2
+ import {StorageType} from "./types";
2
3
 
3
4
  const TEST_KEY = "__check_storage_supported";
4
5
 
@@ -15,26 +16,44 @@ function isSupported(storage?: Storage) {
15
16
  }
16
17
  }
17
18
 
18
- function findSupportedStorage() {
19
- return [window.localStorage, window.sessionStorage].find(isSupported)
20
- || new MemoryStorage();
19
+ function getStorageArea(type: StorageType): Storage {
20
+ const preferred = type === "local" ? window.localStorage : window.sessionStorage;
21
+ const fallback = type === "local" ? window.sessionStorage : window.localStorage;
22
+
23
+ if (isSupported(preferred)) return preferred;
24
+ if (isSupported(fallback)) return fallback;
25
+ return new MemoryStorage();
21
26
  }
22
27
 
23
28
  type StorageChangeListener = (oldValue?: string, newValue?: string) => void;
24
29
 
25
30
  class StorageWrapper {
26
31
  private readonly listeners = new Map<string, Set<StorageChangeListener>>();
27
- private readonly storageArea = findSupportedStorage();
32
+ private readonly storageAreas = new Map<StorageType, Storage>();
28
33
 
29
34
  constructor() {
35
+ // Initialize both storage areas
36
+ this.storageAreas.set("local", getStorageArea("local"));
37
+ this.storageAreas.set("session", getStorageArea("session"));
38
+
30
39
  window.addEventListener("storage", event => {
31
40
  const {storageArea, key, oldValue, newValue} = event;
32
- if (storageArea == this.storageArea && key && oldValue != newValue) {
33
- this.notifyChangeListener(key, oldValue || undefined, newValue || undefined);
41
+ // Check against both storage areas
42
+ if (key && oldValue != newValue) {
43
+ for (const area of this.storageAreas.values()) {
44
+ if (storageArea === area) {
45
+ this.notifyChangeListener(key, oldValue || undefined, newValue || undefined);
46
+ break;
47
+ }
48
+ }
34
49
  }
35
50
  });
36
51
  }
37
52
 
53
+ private getArea(type?: StorageType): Storage {
54
+ return this.storageAreas.get(type ?? "local")!;
55
+ }
56
+
38
57
  addChangeListener(key: string, listener: StorageChangeListener) {
39
58
  this.getOrCreateListeners(key).add(listener);
40
59
  }
@@ -43,13 +62,14 @@ class StorageWrapper {
43
62
  this.getOrCreateListeners(key).delete(listener);
44
63
  }
45
64
 
46
- write(key: string, value?: string) {
47
- const oldValue = this.read(key);
65
+ write(key: string, value?: string, type?: StorageType) {
66
+ const oldValue = this.read(key, type);
67
+ const area = this.getArea(type);
48
68
  try {
49
69
  if (value !== undefined) {
50
- this.storageArea.setItem(key, value);
70
+ area.setItem(key, value);
51
71
  } else {
52
- this.storageArea.removeItem(key);
72
+ area.removeItem(key);
53
73
  }
54
74
  this.notifyChangeListener(key, oldValue, value);
55
75
  } catch (error) {
@@ -57,19 +77,21 @@ class StorageWrapper {
57
77
  }
58
78
  }
59
79
 
60
- delete(key: string) {
61
- const oldValue = this.read(key);
80
+ delete(key: string, type?: StorageType) {
81
+ const oldValue = this.read(key, type);
82
+ const area = this.getArea(type);
62
83
  try {
63
- this.storageArea.removeItem(key);
84
+ area.removeItem(key);
64
85
  this.notifyChangeListener(key, oldValue, undefined);
65
86
  } catch (error) {
66
87
  // ignore error
67
88
  }
68
89
  }
69
90
 
70
- read(key: string) {
91
+ read(key: string, type?: StorageType) {
92
+ const area = this.getArea(type);
71
93
  try {
72
- return this.storageArea.getItem(key);
94
+ return area.getItem(key);
73
95
  } catch (error) {
74
96
  // ignore error
75
97
  return null;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The type of browser storage to use.
3
+ * - 'local': Uses localStorage (persists across browser sessions)
4
+ * - 'session': Uses sessionStorage (cleared when tab closes)
5
+ */
6
+ export type StorageType = "local" | "session";
@@ -1,13 +1,14 @@
1
1
  import {useCallback, useLayoutEffect, useMemo, useState} from "react";
2
2
  import {storage} from "./storage";
3
+ import {StorageType} from "./types";
3
4
 
4
- export function useStorage<T>(key: string, defaultValue: T): [T, (newValue: T) => void] {
5
+ export function useStorage<T>(key: string, defaultValue: T, storageType?: StorageType): [T, (newValue: T) => void] {
5
6
  const defaultValueSerialized = useMemo(() => JSON.stringify(defaultValue), [defaultValue]);
6
7
 
7
8
  const readStateFromStorage = useCallback(() => {
8
- const storageValue = storage.read(key);
9
+ const storageValue = storage.read(key, storageType);
9
10
  return storageValue ?? defaultValueSerialized;
10
- }, [key, defaultValueSerialized]);
11
+ }, [key, defaultValueSerialized, storageType]);
11
12
 
12
13
  const [value, setValue] = useState(readStateFromStorage);
13
14
 
@@ -25,11 +26,25 @@ export function useStorage<T>(key: string, defaultValue: T): [T, (newValue: T) =
25
26
  const setTypedValue = useCallback((newValue: T) => {
26
27
  const value = JSON.stringify(newValue);
27
28
  if (value != defaultValueSerialized) {
28
- storage.write(key, value);
29
+ storage.write(key, value, storageType);
29
30
  } else {
30
- storage.delete(key);
31
+ storage.delete(key, storageType);
31
32
  }
32
- }, [key, defaultValueSerialized]);
33
+ }, [key, defaultValueSerialized, storageType]);
33
34
 
34
35
  return [typedValue, setTypedValue];
35
36
  }
37
+
38
+ /**
39
+ * Convenience hook for localStorage. Equivalent to `useStorage(key, defaultValue, "local")`.
40
+ */
41
+ export function useLocalStorage<T>(key: string, defaultValue: T): [T, (newValue: T) => void] {
42
+ return useStorage(key, defaultValue, "local");
43
+ }
44
+
45
+ /**
46
+ * Convenience hook for sessionStorage. Equivalent to `useStorage(key, defaultValue, "session")`.
47
+ */
48
+ export function useSessionStorage<T>(key: string, defaultValue: T): [T, (newValue: T) => void] {
49
+ return useStorage(key, defaultValue, "session");
50
+ }