@alepha/ui 0.13.6 → 0.13.8

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 (157) hide show
  1. package/dist/admin/AdminAudits-CwvH8e8c.js +215 -0
  2. package/dist/admin/AdminAudits-CwvH8e8c.js.map +1 -0
  3. package/dist/admin/AdminAudits-Dv8Vk_6r.js +3 -0
  4. package/dist/admin/AdminFiles-5CPA3lQk.js +3 -0
  5. package/dist/admin/{AdminFiles-B_jfB_Py.js → AdminFiles-C_w1tb_x.js} +4 -3
  6. package/dist/admin/AdminFiles-C_w1tb_x.js.map +1 -0
  7. package/dist/admin/AdminLayout-BnSmtA4x.js +3 -0
  8. package/dist/admin/AdminLayout-XiSivwWH.js +39 -0
  9. package/dist/admin/AdminLayout-XiSivwWH.js.map +1 -0
  10. package/dist/admin/AdminNotifications-DLjmZWtf.js +3 -0
  11. package/dist/admin/{AdminNotifications-BFEjqpqx.js → AdminNotifications-DuYy74AN.js} +3 -3
  12. package/dist/admin/AdminNotifications-DuYy74AN.js.map +1 -0
  13. package/dist/admin/AdminParameters-DYg48Jwe.js +3 -0
  14. package/dist/admin/AdminParameters-YagqWTG3.js +575 -0
  15. package/dist/admin/AdminParameters-YagqWTG3.js.map +1 -0
  16. package/dist/admin/{AdminSessions-D7DESfWK.js → AdminSessions-BCjgJ-93.js} +4 -4
  17. package/dist/admin/AdminSessions-BCjgJ-93.js.map +1 -0
  18. package/dist/admin/AdminSessions-DEh2uN-4.js +3 -0
  19. package/dist/admin/AdminUserAudits-B_PUXCKC.js +177 -0
  20. package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +1 -0
  21. package/dist/admin/AdminUserAudits-D7cTcElL.js +3 -0
  22. package/dist/admin/{AdminUserCreate-Bhxsn92l.js → AdminUserCreate-DzfRbGZ4.js} +4 -4
  23. package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +1 -0
  24. package/dist/admin/{AdminUserCreate-CYI_xW5T.js → AdminUserCreate-oUA1KDIl.js} +1 -1
  25. package/dist/admin/{AdminUserDetails-C2y1Ig4n.js → AdminUserDetails-DeTrJm-t.js} +5 -5
  26. package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +1 -0
  27. package/dist/admin/{AdminUserDetails-Cmzx9HxH.js → AdminUserDetails-y1H5DW8Y.js} +1 -1
  28. package/dist/admin/{AdminUserLayout-sW6cjZL0.js → AdminUserLayout-CsfrrZkD.js} +4 -7
  29. package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +1 -0
  30. package/dist/admin/{AdminUserLayout-DGSf612u.js → AdminUserLayout-Dejnz13m.js} +1 -1
  31. package/dist/admin/AdminUserSessions-Bbhcpz4k.js +3 -0
  32. package/dist/admin/{AdminUserSessions-CvN15wPe.js → AdminUserSessions-DO9H85O-.js} +4 -4
  33. package/dist/admin/AdminUserSessions-DO9H85O-.js.map +1 -0
  34. package/dist/admin/{AdminUserSettings-DvaaxgcV.js → AdminUserSettings-B3jA8g3p.js} +4 -4
  35. package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +1 -0
  36. package/dist/admin/AdminUserSettings-CE0xpbQc.js +3 -0
  37. package/dist/admin/AdminUsers-CegGZDhW.js +3 -0
  38. package/dist/admin/{AdminUsers-BR3C-jrg.js → AdminUsers-ebbrJBT0.js} +13 -17
  39. package/dist/admin/AdminUsers-ebbrJBT0.js.map +1 -0
  40. package/dist/admin/index.d.ts +2700 -1178
  41. package/dist/admin/index.js +65 -62
  42. package/dist/admin/index.js.map +1 -1
  43. package/dist/auth/AuthLayout-BAZJHzDG.js +23 -0
  44. package/dist/auth/AuthLayout-BAZJHzDG.js.map +1 -0
  45. package/dist/auth/{Login-7HlBjDeV.js → Login-CeNZZjrr.js} +80 -44
  46. package/dist/auth/Login-CeNZZjrr.js.map +1 -0
  47. package/dist/auth/Login-hQcu1nlu.js +4 -0
  48. package/dist/auth/Register-B6HBNVHS.js +4 -0
  49. package/dist/auth/{Register-CuQr3kgi.js → Register-s4ENeyiE.js} +131 -91
  50. package/dist/auth/Register-s4ENeyiE.js.map +1 -0
  51. package/dist/auth/ResetPassword-Cjd-W-Nu.js +3 -0
  52. package/dist/auth/ResetPassword-GLIFkJT7.js +278 -0
  53. package/dist/auth/ResetPassword-GLIFkJT7.js.map +1 -0
  54. package/dist/auth/index.d.ts +605 -532
  55. package/dist/auth/index.js +26 -18
  56. package/dist/auth/index.js.map +1 -1
  57. package/dist/core/index.d.ts +425 -155
  58. package/dist/core/index.js +1751 -1369
  59. package/dist/core/index.js.map +1 -1
  60. package/package.json +23 -20
  61. package/src/admin/AdminRouter.ts +70 -16
  62. package/src/admin/components/AdminLayout.tsx +41 -61
  63. package/src/admin/components/audits/AdminAudits.tsx +240 -0
  64. package/src/admin/components/{AdminFiles.tsx → files/AdminFiles.tsx} +1 -1
  65. package/src/admin/components/{AdminJobs.tsx → jobs/AdminJobs.tsx} +1 -1
  66. package/src/admin/components/parameters/AdminParameters.tsx +137 -0
  67. package/src/admin/components/parameters/ParameterDetails.tsx +228 -0
  68. package/src/admin/components/parameters/ParameterHistory.tsx +146 -0
  69. package/src/admin/components/parameters/ParameterTree.tsx +146 -0
  70. package/src/admin/components/parameters/types.ts +35 -0
  71. package/src/admin/components/{AdminSessions.tsx → sessions/AdminSessions.tsx} +1 -1
  72. package/src/admin/components/users/AdminUserAudits.tsx +183 -0
  73. package/src/admin/components/{AdminUserCreate.tsx → users/AdminUserCreate.tsx} +1 -1
  74. package/src/admin/components/{AdminUserLayout.tsx → users/AdminUserLayout.tsx} +1 -4
  75. package/src/admin/components/{AdminUserSettings.tsx → users/AdminUserSettings.tsx} +1 -1
  76. package/src/admin/components/{AdminUsers.tsx → users/AdminUsers.tsx} +10 -12
  77. package/src/admin/index.ts +24 -16
  78. package/src/auth/AuthRouter.ts +23 -17
  79. package/src/auth/components/AuthLayout.tsx +6 -3
  80. package/src/auth/components/Login.tsx +109 -47
  81. package/src/auth/components/Register.tsx +158 -94
  82. package/src/auth/components/ResetPassword.tsx +51 -5
  83. package/src/auth/components/buttons/UserButton.tsx +2 -0
  84. package/src/core/atoms/alephaThemeAtom.ts +13 -0
  85. package/src/core/atoms/alephaThemeListAtom.ts +10 -0
  86. package/src/core/atoms/themes/default.ts +6 -0
  87. package/src/core/{themes → atoms/themes}/midnight.ts +3 -5
  88. package/src/core/components/buttons/ActionButton.tsx +33 -26
  89. package/src/core/components/buttons/DarkModeButton.tsx +0 -1
  90. package/src/core/components/buttons/ThemeButton.tsx +10 -7
  91. package/src/core/components/buttons/ToggleSidebarButton.tsx +19 -16
  92. package/src/core/components/data/ErrorViewer.tsx +171 -0
  93. package/src/core/components/data/JsonViewer.tsx +147 -138
  94. package/src/core/components/form/Control.tsx +95 -18
  95. package/src/core/components/form/ControlArray.tsx +377 -0
  96. package/src/core/components/form/ControlObject.tsx +127 -0
  97. package/src/core/components/form/TypeForm.tsx +99 -37
  98. package/src/core/components/layout/AdminShell.tsx +14 -1
  99. package/src/core/components/layout/AlephaMantineProvider.tsx +7 -3
  100. package/src/core/components/layout/Omnibar.tsx +1 -1
  101. package/src/core/components/layout/Sidebar.tsx +47 -14
  102. package/src/core/components/table/ColumnPicker.tsx +126 -0
  103. package/src/core/components/table/DataTable.tsx +354 -181
  104. package/src/core/components/table/DataTableFilters.tsx +64 -0
  105. package/src/core/components/table/DataTablePagination.tsx +59 -0
  106. package/src/core/components/table/DataTableToolbar.tsx +126 -0
  107. package/src/core/components/table/FilterPicker.tsx +138 -0
  108. package/src/core/components/table/types.ts +199 -0
  109. package/src/core/helpers/isComponentType.ts +9 -0
  110. package/src/core/helpers/renderIcon.tsx +13 -0
  111. package/src/core/hooks/useTheme.ts +24 -18
  112. package/src/core/index.ts +24 -3
  113. package/src/core/interfaces/AlephaTheme.ts +8 -0
  114. package/src/core/providers/ThemeProvider.ts +44 -62
  115. package/src/core/services/DialogService.tsx +24 -0
  116. package/src/core/utils/parseInput.ts +2 -2
  117. package/styles.css +1 -1
  118. package/dist/admin/AdminFiles-B-0UcHVV.js +0 -3
  119. package/dist/admin/AdminFiles-B_jfB_Py.js.map +0 -1
  120. package/dist/admin/AdminLayout-BMtiXAzS.js +0 -396
  121. package/dist/admin/AdminLayout-BMtiXAzS.js.map +0 -1
  122. package/dist/admin/AdminLayout-BNo3GoHR.js +0 -3
  123. package/dist/admin/AdminNotifications-BFEjqpqx.js.map +0 -1
  124. package/dist/admin/AdminNotifications-DJs2ZjNj.js +0 -3
  125. package/dist/admin/AdminSessions-D7DESfWK.js.map +0 -1
  126. package/dist/admin/AdminSessions-PS2M8iXi.js +0 -3
  127. package/dist/admin/AdminUserCreate-Bhxsn92l.js.map +0 -1
  128. package/dist/admin/AdminUserDetails-C2y1Ig4n.js.map +0 -1
  129. package/dist/admin/AdminUserLayout-sW6cjZL0.js.map +0 -1
  130. package/dist/admin/AdminUserSessions-CvN15wPe.js.map +0 -1
  131. package/dist/admin/AdminUserSessions-D-aOcZgV.js +0 -3
  132. package/dist/admin/AdminUserSettings-CEMhIYrI.js +0 -3
  133. package/dist/admin/AdminUserSettings-DvaaxgcV.js.map +0 -1
  134. package/dist/admin/AdminUsers-BR3C-jrg.js.map +0 -1
  135. package/dist/admin/AdminUsers-CMW9vN09.js +0 -3
  136. package/dist/auth/AuthLayout-CzwUKD9y.js +0 -19
  137. package/dist/auth/AuthLayout-CzwUKD9y.js.map +0 -1
  138. package/dist/auth/Login-7HlBjDeV.js.map +0 -1
  139. package/dist/auth/Login-C-e27DGb.js +0 -4
  140. package/dist/auth/Register-CuQr3kgi.js.map +0 -1
  141. package/dist/auth/Register-DbvXwgbG.js +0 -4
  142. package/dist/auth/ResetPassword-BzU-cdd4.js +0 -243
  143. package/dist/auth/ResetPassword-BzU-cdd4.js.map +0 -1
  144. package/dist/auth/ResetPassword-DSvrdpaA.js +0 -3
  145. package/src/admin/AdminSidebar.ts +0 -31
  146. package/src/admin/components/AdminParameters.tsx +0 -24
  147. package/src/core/themes/aurora.ts +0 -107
  148. package/src/core/themes/crystal.ts +0 -107
  149. package/src/core/themes/default.ts +0 -7
  150. package/src/core/themes/ember.ts +0 -107
  151. package/src/core/themes/index.ts +0 -7
  152. package/src/core/themes/remoraid.ts +0 -278
  153. package/src/core/themes/slate.ts +0 -81
  154. /package/src/admin/components/{AdminNotifications.tsx → notifications/AdminNotifications.tsx} +0 -0
  155. /package/src/admin/components/{AdminUserDetails.tsx → users/AdminUserDetails.tsx} +0 -0
  156. /package/src/admin/components/{AdminUserSessions.tsx → users/AdminUserSessions.tsx} +0 -0
  157. /package/src/admin/components/{AdminVerifications.tsx → verifications/AdminVerifications.tsx} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { useStore } from "@alepha/react";
2
+ import { Flex } from "@mantine/core";
2
3
  import {
3
4
  IconLayoutSidebarLeftCollapse,
4
5
  IconLayoutSidebarRightCollapse,
@@ -9,22 +10,24 @@ const ToggleSidebarButton = () => {
9
10
  const [collapsed, setCollapsed] = useStore("alepha.ui.sidebar.collapsed");
10
11
 
11
12
  return (
12
- <ActionButton
13
- icon={
14
- collapsed ? (
15
- <IconLayoutSidebarRightCollapse />
16
- ) : (
17
- <IconLayoutSidebarLeftCollapse />
18
- )
19
- }
20
- variant={"subtle"}
21
- size={"md"}
22
- onClick={() => setCollapsed(!collapsed)}
23
- tooltip={{
24
- position: "right",
25
- label: collapsed ? "Show sidebar" : "Hide sidebar",
26
- }}
27
- />
13
+ <Flex>
14
+ <ActionButton
15
+ icon={
16
+ collapsed ? (
17
+ <IconLayoutSidebarRightCollapse />
18
+ ) : (
19
+ <IconLayoutSidebarLeftCollapse />
20
+ )
21
+ }
22
+ variant={"subtle"}
23
+ size={"md"}
24
+ onClick={() => setCollapsed(!collapsed)}
25
+ tooltip={{
26
+ position: "right",
27
+ label: collapsed ? "Show sidebar" : "Hide sidebar",
28
+ }}
29
+ />
30
+ </Flex>
28
31
  );
29
32
  };
30
33
 
@@ -0,0 +1,171 @@
1
+ import {
2
+ ActionIcon,
3
+ Box,
4
+ Collapse,
5
+ CopyButton,
6
+ type MantineSize,
7
+ Text,
8
+ Tooltip,
9
+ } from "@mantine/core";
10
+ import {
11
+ IconCheck,
12
+ IconChevronDown,
13
+ IconChevronRight,
14
+ IconCopy,
15
+ } from "@tabler/icons-react";
16
+ import { useState } from "react";
17
+
18
+ interface ErrorViewerProps {
19
+ error: Error | unknown;
20
+ showStack?: boolean;
21
+ copyable?: boolean;
22
+ size?: MantineSize;
23
+ }
24
+
25
+ const getSizeConfig = (size: MantineSize = "sm") => {
26
+ const configs = {
27
+ xs: { text: "xs", icon: 12, gap: 2 },
28
+ sm: { text: "sm", icon: 14, gap: 4 },
29
+ md: { text: "md", icon: 16, gap: 6 },
30
+ lg: { text: "lg", icon: 18, gap: 8 },
31
+ xl: { text: "xl", icon: 20, gap: 10 },
32
+ };
33
+ return configs[size] || configs.sm;
34
+ };
35
+
36
+ const parseStackTrace = (stack: string): string[] => {
37
+ return stack
38
+ .split("\n")
39
+ .map((line) => line.trim())
40
+ .filter((line) => line.length > 0);
41
+ };
42
+
43
+ export const ErrorViewer = ({
44
+ error,
45
+ showStack = true,
46
+ copyable = true,
47
+ size = "sm",
48
+ }: ErrorViewerProps) => {
49
+ const [stackExpanded, setStackExpanded] = useState(false);
50
+ const sizeConfig = getSizeConfig(size);
51
+ const copyIconSize = sizeConfig.icon + 2;
52
+
53
+ const isError = error instanceof Error;
54
+ const errorName = isError ? error.name : "Error";
55
+ const errorMessage = isError ? error.message : String(error);
56
+ const errorStack = isError ? error.stack : undefined;
57
+ const stackLines = errorStack ? parseStackTrace(errorStack) : [];
58
+
59
+ const getCopyContent = () => {
60
+ if (isError) {
61
+ return `${errorName}: ${errorMessage}${errorStack ? `\n\n${errorStack}` : ""}`;
62
+ }
63
+ return String(error);
64
+ };
65
+
66
+ return (
67
+ <Box pos="relative" w="100%">
68
+ {copyable && (
69
+ <Box pos="absolute" top={0} right={0} style={{ zIndex: 1 }}>
70
+ <CopyButton value={getCopyContent()}>
71
+ {({ copied, copy }) => (
72
+ <Tooltip label={copied ? "Copied" : "Copy Error"}>
73
+ <ActionIcon
74
+ color={copied ? "teal" : "gray"}
75
+ variant="subtle"
76
+ onClick={copy}
77
+ size={size}
78
+ >
79
+ {copied ? (
80
+ <IconCheck size={copyIconSize} />
81
+ ) : (
82
+ <IconCopy size={copyIconSize} />
83
+ )}
84
+ </ActionIcon>
85
+ </Tooltip>
86
+ )}
87
+ </CopyButton>
88
+ </Box>
89
+ )}
90
+ <Box pt={copyable ? 30 : 0}>
91
+ <Box
92
+ style={{
93
+ display: "flex",
94
+ alignItems: "flex-start",
95
+ gap: sizeConfig.gap,
96
+ }}
97
+ >
98
+ <Text
99
+ component="span"
100
+ c="red"
101
+ ff="monospace"
102
+ fw={600}
103
+ size={sizeConfig.text}
104
+ >
105
+ {errorName}:
106
+ </Text>
107
+ <Text
108
+ component="span"
109
+ ff="monospace"
110
+ size={sizeConfig.text}
111
+ style={{ wordBreak: "break-word" }}
112
+ >
113
+ {errorMessage}
114
+ </Text>
115
+ </Box>
116
+
117
+ {showStack && stackLines.length > 1 && (
118
+ <Box mt="sm">
119
+ <Box
120
+ style={{
121
+ display: "flex",
122
+ alignItems: "center",
123
+ gap: sizeConfig.gap,
124
+ cursor: "pointer",
125
+ }}
126
+ onClick={() => setStackExpanded(!stackExpanded)}
127
+ >
128
+ <ActionIcon size="xs" variant="transparent" c="dimmed">
129
+ {stackExpanded ? (
130
+ <IconChevronDown size={sizeConfig.icon} />
131
+ ) : (
132
+ <IconChevronRight size={sizeConfig.icon} />
133
+ )}
134
+ </ActionIcon>
135
+ <Text c="dimmed" size={sizeConfig.text} fw={500}>
136
+ Stack Trace ({stackLines.length - 1} frames)
137
+ </Text>
138
+ </Box>
139
+
140
+ <Collapse in={stackExpanded}>
141
+ <Box
142
+ mt="xs"
143
+ pl="md"
144
+ style={{
145
+ borderLeft: "1px solid var(--mantine-color-default-border)",
146
+ }}
147
+ >
148
+ {stackLines.slice(1).map((line, index) => (
149
+ <Text
150
+ key={index}
151
+ ff="monospace"
152
+ size="xs"
153
+ c="dimmed"
154
+ style={{
155
+ whiteSpace: "pre-wrap",
156
+ wordBreak: "break-all",
157
+ }}
158
+ >
159
+ {line}
160
+ </Text>
161
+ ))}
162
+ </Box>
163
+ </Collapse>
164
+ </Box>
165
+ )}
166
+ </Box>
167
+ </Box>
168
+ );
169
+ };
170
+
171
+ export default ErrorViewer;
@@ -31,15 +31,16 @@ interface JsonNodeProps {
31
31
  isLast?: boolean;
32
32
  isArrayItem?: boolean;
33
33
  size?: MantineSize;
34
+ iconWidth: number;
34
35
  }
35
36
 
36
37
  const getSizeConfig = (size: MantineSize = "sm") => {
37
38
  const configs = {
38
- xs: { text: "xs", icon: 12, indent: 16, gap: 2 },
39
- sm: { text: "sm", icon: 14, indent: 20, gap: 4 },
40
- md: { text: "md", icon: 16, indent: 24, gap: 6 },
41
- lg: { text: "lg", icon: 18, indent: 28, gap: 8 },
42
- xl: { text: "xl", icon: 20, indent: 32, gap: 10 },
39
+ xs: { text: "xs" as const, icon: 12, indent: 16, gap: 4, iconWidth: 18 },
40
+ sm: { text: "sm" as const, icon: 14, indent: 20, gap: 6, iconWidth: 20 },
41
+ md: { text: "md" as const, icon: 16, indent: 24, gap: 8, iconWidth: 22 },
42
+ lg: { text: "lg" as const, icon: 18, indent: 28, gap: 10, iconWidth: 24 },
43
+ xl: { text: "xl" as const, icon: 20, indent: 32, gap: 12, iconWidth: 26 },
43
44
  };
44
45
  return configs[size] || configs.sm;
45
46
  };
@@ -52,6 +53,7 @@ const JsonNode = ({
52
53
  isLast = false,
53
54
  isArrayItem = false,
54
55
  size = "sm",
56
+ iconWidth,
55
57
  }: JsonNodeProps) => {
56
58
  const [expanded, setExpanded] = useState(depth < 2);
57
59
  const sizeConfig = getSizeConfig(size);
@@ -68,83 +70,50 @@ const JsonNode = ({
68
70
  const renderPrimitive = (val: any): ReactNode => {
69
71
  const type = getValueType(val);
70
72
 
73
+ const textProps = {
74
+ component: "span" as const,
75
+ ff: "monospace" as const,
76
+ size: sizeConfig.text,
77
+ };
78
+
71
79
  switch (type) {
72
80
  case "string":
73
81
  return (
74
- <Text
75
- component="span"
76
- c="teal"
77
- ff="monospace"
78
- size={sizeConfig.text}
79
- style={{ whiteSpace: "nowrap" }}
80
- >
82
+ <Text {...textProps} c="teal">
81
83
  "{val}"
82
84
  </Text>
83
85
  );
84
86
  case "number":
85
87
  return (
86
- <Text
87
- component="span"
88
- c="blue"
89
- ff="monospace"
90
- size={sizeConfig.text}
91
- style={{ whiteSpace: "nowrap" }}
92
- >
88
+ <Text {...textProps} c="blue">
93
89
  {val}
94
90
  </Text>
95
91
  );
96
92
  case "boolean":
97
93
  return (
98
- <Text
99
- component="span"
100
- c="violet"
101
- ff="monospace"
102
- size={sizeConfig.text}
103
- style={{ whiteSpace: "nowrap" }}
104
- >
94
+ <Text {...textProps} c="violet">
105
95
  {String(val)}
106
96
  </Text>
107
97
  );
108
98
  case "null":
109
99
  return (
110
- <Text
111
- component="span"
112
- c="dimmed"
113
- ff="monospace"
114
- size={sizeConfig.text}
115
- style={{ whiteSpace: "nowrap" }}
116
- >
100
+ <Text {...textProps} c="dimmed">
117
101
  null
118
102
  </Text>
119
103
  );
120
104
  case "undefined":
121
105
  return (
122
- <Text
123
- component="span"
124
- c="dimmed"
125
- ff="monospace"
126
- size={sizeConfig.text}
127
- style={{ whiteSpace: "nowrap" }}
128
- >
106
+ <Text {...textProps} c="dimmed">
129
107
  undefined
130
108
  </Text>
131
109
  );
132
110
  default:
133
- return (
134
- <Text
135
- component="span"
136
- ff="monospace"
137
- size={sizeConfig.text}
138
- style={{ whiteSpace: "nowrap" }}
139
- >
140
- {String(val)}
141
- </Text>
142
- );
111
+ return <Text {...textProps}>{String(val)}</Text>;
143
112
  }
144
113
  };
145
114
 
146
115
  const renderKey = () => {
147
- if (!name) return null;
116
+ if (name === undefined) return null;
148
117
  return (
149
118
  <Text
150
119
  component="span"
@@ -153,11 +122,17 @@ const JsonNode = ({
153
122
  fw={500}
154
123
  size={sizeConfig.text}
155
124
  >
156
- {isArrayItem ? `[${name}]` : `"${name}"`}:
125
+ {isArrayItem ? `[${name}]` : `"${name}"`}
157
126
  </Text>
158
127
  );
159
128
  };
160
129
 
130
+ const comma = !isLast && (
131
+ <Text component="span" c="dimmed" ff="monospace" size={sizeConfig.text}>
132
+ ,
133
+ </Text>
134
+ );
135
+
161
136
  if (valueType === "object" || valueType === "array") {
162
137
  const isObject = valueType === "object";
163
138
  const entries = isObject
@@ -173,81 +148,98 @@ const JsonNode = ({
173
148
  <Box>
174
149
  <Box
175
150
  style={{
176
- display: "flex",
151
+ display: "grid",
152
+ gridTemplateColumns: `${iconWidth}px auto`,
177
153
  alignItems: "center",
178
- gap: sizeConfig.gap,
179
- minWidth: "max-content",
180
154
  }}
181
155
  >
182
- {canExpand && (
183
- <ActionIcon
184
- size="xs"
185
- variant="transparent"
186
- c="dimmed"
187
- onClick={() => setExpanded(!expanded)}
188
- style={{ cursor: "pointer", flexShrink: 0 }}
189
- >
190
- {expanded ? (
191
- <IconChevronDown size={sizeConfig.icon} />
192
- ) : (
193
- <IconChevronRight size={sizeConfig.icon} />
194
- )}
195
- </ActionIcon>
196
- )}
197
- {!canExpand && (
198
- <Box w={sizeConfig.icon + 6} style={{ flexShrink: 0 }} />
199
- )}
200
- <Box style={{ flexShrink: 0 }}>{renderKey()}</Box>{" "}
201
- <Text
202
- component="span"
203
- c="dimmed"
204
- ff="monospace"
205
- size={sizeConfig.text}
206
- style={{ flexShrink: 0 }}
156
+ <Box
157
+ style={{
158
+ display: "flex",
159
+ justifyContent: "center",
160
+ alignItems: "center",
161
+ }}
207
162
  >
208
- {brackets[0]}
209
- </Text>
210
- {!expanded && !isEmpty && (
211
- <Text
212
- component="span"
213
- c="dimmed"
214
- ff="monospace"
215
- fs="italic"
216
- size={sizeConfig.text}
217
- style={{ flexShrink: 0 }}
218
- >
219
- {preview}
220
- </Text>
221
- )}
222
- {(isEmpty || !expanded) && (
163
+ {canExpand && (
164
+ <ActionIcon
165
+ size="xs"
166
+ variant="transparent"
167
+ c="dimmed"
168
+ onClick={() => setExpanded(!expanded)}
169
+ style={{ cursor: "pointer" }}
170
+ >
171
+ {expanded ? (
172
+ <IconChevronDown size={sizeConfig.icon} />
173
+ ) : (
174
+ <IconChevronRight size={sizeConfig.icon} />
175
+ )}
176
+ </ActionIcon>
177
+ )}
178
+ </Box>
179
+ <Box
180
+ style={{
181
+ display: "flex",
182
+ alignItems: "center",
183
+ gap: sizeConfig.gap,
184
+ }}
185
+ >
186
+ {renderKey()}
187
+ {name !== undefined && (
188
+ <Text
189
+ component="span"
190
+ c="dimmed"
191
+ ff="monospace"
192
+ size={sizeConfig.text}
193
+ >
194
+ :
195
+ </Text>
196
+ )}
223
197
  <Text
224
198
  component="span"
225
199
  c="dimmed"
226
200
  ff="monospace"
227
201
  size={sizeConfig.text}
228
- style={{ flexShrink: 0 }}
229
- >
230
- {brackets[1]}
231
- </Text>
232
- )}
233
- {!isEmpty && !expanded && (
234
- <Text
235
- component="span"
236
- c="dimmed"
237
- size={sizeConfig.text}
238
- style={{ flexShrink: 0 }}
239
202
  >
240
- {entries.length} {entries.length === 1 ? "item" : "items"}
203
+ {brackets[0]}
241
204
  </Text>
242
- )}
205
+ {!expanded && !isEmpty && (
206
+ <Text
207
+ component="span"
208
+ c="dimmed"
209
+ ff="monospace"
210
+ fs="italic"
211
+ size={sizeConfig.text}
212
+ >
213
+ {preview}
214
+ </Text>
215
+ )}
216
+ {(isEmpty || !expanded) && (
217
+ <>
218
+ <Text
219
+ component="span"
220
+ c="dimmed"
221
+ ff="monospace"
222
+ size={sizeConfig.text}
223
+ >
224
+ {brackets[1]}
225
+ </Text>
226
+ {comma}
227
+ </>
228
+ )}
229
+ {!isEmpty && !expanded && (
230
+ <Text component="span" c="dimmed" size={sizeConfig.text}>
231
+ {entries.length} {entries.length === 1 ? "item" : "items"}
232
+ </Text>
233
+ )}
234
+ </Box>
243
235
  </Box>
244
236
 
245
237
  <Collapse in={expanded && canExpand}>
246
238
  <Box
247
239
  pl={sizeConfig.indent}
240
+ ml={iconWidth / 2}
248
241
  style={{
249
242
  borderLeft: "1px solid var(--mantine-color-default-border)",
250
- marginLeft: Math.floor((sizeConfig.icon + 6) / 2),
251
243
  }}
252
244
  >
253
245
  {entries.map(
@@ -261,20 +253,24 @@ const JsonNode = ({
261
253
  isLast={index === entries.length - 1}
262
254
  isArrayItem={!isObject}
263
255
  size={size}
256
+ iconWidth={iconWidth}
264
257
  />
265
258
  ),
266
259
  )}
267
260
  </Box>
268
- <Box style={{ display: "flex", minWidth: "max-content" }}>
269
- <Box w={sizeConfig.icon + 6} style={{ flexShrink: 0 }} />
270
- <Text
271
- c="dimmed"
272
- ff="monospace"
273
- size={sizeConfig.text}
274
- style={{ flexShrink: 0 }}
275
- >
276
- {brackets[1]}
277
- </Text>
261
+ <Box
262
+ style={{
263
+ display: "grid",
264
+ gridTemplateColumns: `${iconWidth}px auto`,
265
+ }}
266
+ >
267
+ <Box />
268
+ <Box style={{ display: "flex", gap: sizeConfig.gap }}>
269
+ <Text c="dimmed" ff="monospace" size={sizeConfig.text}>
270
+ {brackets[1]}
271
+ </Text>
272
+ {comma}
273
+ </Box>
278
274
  </Box>
279
275
  </Collapse>
280
276
  </Box>
@@ -284,26 +280,33 @@ const JsonNode = ({
284
280
  return (
285
281
  <Box
286
282
  style={{
287
- display: "flex",
283
+ display: "grid",
284
+ gridTemplateColumns: `${iconWidth}px auto`,
288
285
  alignItems: "center",
289
- gap: sizeConfig.gap,
290
- minWidth: "max-content",
291
286
  }}
292
287
  >
293
- <Box w={sizeConfig.icon + 6} style={{ flexShrink: 0 }} />
294
- <Box style={{ flexShrink: 0 }}>{renderKey()}</Box>
295
- <Box style={{ flexShrink: 0 }}>{renderPrimitive(value)}</Box>
296
- {!isLast && (
297
- <Text
298
- component="span"
299
- c="dimmed"
300
- ff="monospace"
301
- size={sizeConfig.text}
302
- style={{ flexShrink: 0 }}
303
- >
304
- ,
305
- </Text>
306
- )}
288
+ <Box />
289
+ <Box
290
+ style={{
291
+ display: "flex",
292
+ alignItems: "center",
293
+ gap: sizeConfig.gap,
294
+ }}
295
+ >
296
+ {renderKey()}
297
+ {name !== undefined && (
298
+ <Text
299
+ component="span"
300
+ c="dimmed"
301
+ ff="monospace"
302
+ size={sizeConfig.text}
303
+ >
304
+ :
305
+ </Text>
306
+ )}
307
+ {renderPrimitive(value)}
308
+ {comma}
309
+ </Box>
307
310
  </Box>
308
311
  );
309
312
  };
@@ -319,7 +322,7 @@ export const JsonViewer = ({
319
322
  const copyIconSize = sizeConfig.icon + 2;
320
323
 
321
324
  return (
322
- <Box pos="relative" w={"100%"}>
325
+ <Box pos="relative" w="100%">
323
326
  {copyable && (
324
327
  <Box pos="absolute" top={0} right={0} style={{ zIndex: 1 }}>
325
328
  <CopyButton value={JSON.stringify(data, null, 2)}>
@@ -343,7 +346,13 @@ export const JsonViewer = ({
343
346
  </Box>
344
347
  )}
345
348
  <Box pt={copyable ? 30 : 0} style={{ overflowX: "auto" }}>
346
- <JsonNode value={data} depth={0} maxDepth={maxDepth} size={size} />
349
+ <JsonNode
350
+ value={data}
351
+ depth={0}
352
+ maxDepth={maxDepth}
353
+ size={size}
354
+ iconWidth={sizeConfig.iconWidth}
355
+ />
347
356
  </Box>
348
357
  </Box>
349
358
  );