@contember/react-devbar 1.3.0-alpha.14

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 (120) hide show
  1. package/dist/assets/index.css +377 -0
  2. package/dist/development/errorHandling.cjs +58 -0
  3. package/dist/development/errorHandling.cjs.map +1 -0
  4. package/dist/development/errorHandling.js +41 -0
  5. package/dist/development/errorHandling.js.map +1 -0
  6. package/dist/development/hooks/useParsedStacktrace.cjs +62 -0
  7. package/dist/development/hooks/useParsedStacktrace.cjs.map +1 -0
  8. package/dist/development/hooks/useParsedStacktrace.js +40 -0
  9. package/dist/development/hooks/useParsedStacktrace.js.map +1 -0
  10. package/dist/development/index.cjs +17 -0
  11. package/dist/development/index.cjs.map +1 -0
  12. package/dist/development/index.js +17 -0
  13. package/dist/development/index.js.map +1 -0
  14. package/dist/development/ui/DevBar/DevBar.cjs +162 -0
  15. package/dist/development/ui/DevBar/DevBar.cjs.map +1 -0
  16. package/dist/development/ui/DevBar/DevBar.js +162 -0
  17. package/dist/development/ui/DevBar/DevBar.js.map +1 -0
  18. package/dist/development/ui/DevError/DevError.cjs +14 -0
  19. package/dist/development/ui/DevError/DevError.cjs.map +1 -0
  20. package/dist/development/ui/DevError/DevError.js +14 -0
  21. package/dist/development/ui/DevError/DevError.js.map +1 -0
  22. package/dist/development/ui/DevError/DevErrorBadge.cjs +14 -0
  23. package/dist/development/ui/DevError/DevErrorBadge.cjs.map +1 -0
  24. package/dist/development/ui/DevError/DevErrorBadge.js +14 -0
  25. package/dist/development/ui/DevError/DevErrorBadge.js.map +1 -0
  26. package/dist/development/ui/DevError/DevErrorInner.cjs +24 -0
  27. package/dist/development/ui/DevError/DevErrorInner.cjs.map +1 -0
  28. package/dist/development/ui/DevError/DevErrorInner.js +24 -0
  29. package/dist/development/ui/DevError/DevErrorInner.js.map +1 -0
  30. package/dist/development/ui/DevError/DevErrorList.cjs +39 -0
  31. package/dist/development/ui/DevError/DevErrorList.cjs.map +1 -0
  32. package/dist/development/ui/DevError/DevErrorList.js +39 -0
  33. package/dist/development/ui/DevError/DevErrorList.js.map +1 -0
  34. package/dist/development/ui/DevError/StackTrace.cjs +41 -0
  35. package/dist/development/ui/DevError/StackTrace.cjs.map +1 -0
  36. package/dist/development/ui/DevError/StackTrace.js +41 -0
  37. package/dist/development/ui/DevError/StackTrace.js.map +1 -0
  38. package/dist/production/errorHandling.cjs +58 -0
  39. package/dist/production/errorHandling.cjs.map +1 -0
  40. package/dist/production/errorHandling.js +41 -0
  41. package/dist/production/errorHandling.js.map +1 -0
  42. package/dist/production/hooks/useParsedStacktrace.cjs +62 -0
  43. package/dist/production/hooks/useParsedStacktrace.cjs.map +1 -0
  44. package/dist/production/hooks/useParsedStacktrace.js +40 -0
  45. package/dist/production/hooks/useParsedStacktrace.js.map +1 -0
  46. package/dist/production/index.cjs +17 -0
  47. package/dist/production/index.cjs.map +1 -0
  48. package/dist/production/index.js +17 -0
  49. package/dist/production/index.js.map +1 -0
  50. package/dist/production/ui/DevBar/DevBar.cjs +162 -0
  51. package/dist/production/ui/DevBar/DevBar.cjs.map +1 -0
  52. package/dist/production/ui/DevBar/DevBar.js +162 -0
  53. package/dist/production/ui/DevBar/DevBar.js.map +1 -0
  54. package/dist/production/ui/DevError/DevError.cjs +14 -0
  55. package/dist/production/ui/DevError/DevError.cjs.map +1 -0
  56. package/dist/production/ui/DevError/DevError.js +14 -0
  57. package/dist/production/ui/DevError/DevError.js.map +1 -0
  58. package/dist/production/ui/DevError/DevErrorBadge.cjs +14 -0
  59. package/dist/production/ui/DevError/DevErrorBadge.cjs.map +1 -0
  60. package/dist/production/ui/DevError/DevErrorBadge.js +14 -0
  61. package/dist/production/ui/DevError/DevErrorBadge.js.map +1 -0
  62. package/dist/production/ui/DevError/DevErrorInner.cjs +24 -0
  63. package/dist/production/ui/DevError/DevErrorInner.cjs.map +1 -0
  64. package/dist/production/ui/DevError/DevErrorInner.js +24 -0
  65. package/dist/production/ui/DevError/DevErrorInner.js.map +1 -0
  66. package/dist/production/ui/DevError/DevErrorList.cjs +39 -0
  67. package/dist/production/ui/DevError/DevErrorList.cjs.map +1 -0
  68. package/dist/production/ui/DevError/DevErrorList.js +39 -0
  69. package/dist/production/ui/DevError/DevErrorList.js.map +1 -0
  70. package/dist/production/ui/DevError/StackTrace.cjs +41 -0
  71. package/dist/production/ui/DevError/StackTrace.cjs.map +1 -0
  72. package/dist/production/ui/DevError/StackTrace.js +41 -0
  73. package/dist/production/ui/DevError/StackTrace.js.map +1 -0
  74. package/dist/types/DevErrorManager.d.ts +15 -0
  75. package/dist/types/DevErrorManager.d.ts.map +1 -0
  76. package/dist/types/errorHandling.d.ts +6 -0
  77. package/dist/types/errorHandling.d.ts.map +1 -0
  78. package/dist/types/hooks/useParsedStacktrace.d.ts +10 -0
  79. package/dist/types/hooks/useParsedStacktrace.d.ts.map +1 -0
  80. package/dist/types/index.d.ts +5 -0
  81. package/dist/types/index.d.ts.map +1 -0
  82. package/dist/types/tsconfig.tsbuildinfo +1 -0
  83. package/dist/types/ui/DevBar/DevBar.d.ts +12 -0
  84. package/dist/types/ui/DevBar/DevBar.d.ts.map +1 -0
  85. package/dist/types/ui/DevBar/index.d.ts +2 -0
  86. package/dist/types/ui/DevBar/index.d.ts.map +1 -0
  87. package/dist/types/ui/DevError/DevError.d.ts +6 -0
  88. package/dist/types/ui/DevError/DevError.d.ts.map +1 -0
  89. package/dist/types/ui/DevError/DevErrorBadge.d.ts +6 -0
  90. package/dist/types/ui/DevError/DevErrorBadge.d.ts.map +1 -0
  91. package/dist/types/ui/DevError/DevErrorInner.d.ts +7 -0
  92. package/dist/types/ui/DevError/DevErrorInner.d.ts.map +1 -0
  93. package/dist/types/ui/DevError/DevErrorList.d.ts +12 -0
  94. package/dist/types/ui/DevError/DevErrorList.d.ts.map +1 -0
  95. package/dist/types/ui/DevError/StackTrace.d.ts +5 -0
  96. package/dist/types/ui/DevError/StackTrace.d.ts.map +1 -0
  97. package/dist/types/ui/DevError/index.d.ts +5 -0
  98. package/dist/types/ui/DevError/index.d.ts.map +1 -0
  99. package/dist/types/ui/DevError/types.d.ts +15 -0
  100. package/dist/types/ui/DevError/types.d.ts.map +1 -0
  101. package/package.json +64 -0
  102. package/src/DevErrorManager.tsx +82 -0
  103. package/src/errorHandling.tsx +87 -0
  104. package/src/hooks/useParsedStacktrace.ts +40 -0
  105. package/src/index.css +2 -0
  106. package/src/index.ts +4 -0
  107. package/src/tsconfig.json +10 -0
  108. package/src/ui/DevBar/DevBar.tsx +187 -0
  109. package/src/ui/DevBar/index.css +171 -0
  110. package/src/ui/DevBar/index.tsx +1 -0
  111. package/src/ui/DevError/DevError.css +191 -0
  112. package/src/ui/DevError/DevError.tsx +21 -0
  113. package/src/ui/DevError/DevErrorBadge.css +16 -0
  114. package/src/ui/DevError/DevErrorBadge.tsx +18 -0
  115. package/src/ui/DevError/DevErrorInner.tsx +46 -0
  116. package/src/ui/DevError/DevErrorList.tsx +60 -0
  117. package/src/ui/DevError/StackTrace.tsx +49 -0
  118. package/src/ui/DevError/index.css +2 -0
  119. package/src/ui/DevError/index.ts +4 -0
  120. package/src/ui/DevError/types.ts +17 -0
@@ -0,0 +1,187 @@
1
+ import {
2
+ useClassNameFactory,
3
+ useId,
4
+ useOnElementClickOutsideCallback,
5
+ useOnElementMouseEnterDelayedCallback,
6
+ useReferentiallyStableCallback,
7
+ useWindowSize,
8
+ } from '@contember/react-utils'
9
+ import { dataAttribute } from '@contember/utilities'
10
+ import { PropsWithChildren, ReactNode, useEffect, useRef, useState } from 'react'
11
+
12
+ export const DevBar = ({
13
+ breakpoint = 768,
14
+ children,
15
+ brand,
16
+ }: PropsWithChildren<{
17
+ brand?: ReactNode;
18
+ breakpoint?: number;
19
+ }>) => {
20
+ const className = useClassNameFactory('devBar')
21
+ const [expanded, setExpanded] = useState(true)
22
+ const isSmallScreen = useWindowSize().width < breakpoint
23
+ const toggleButtonRef = useRef<HTMLButtonElement>(null)
24
+
25
+ const handleToggle = useReferentiallyStableCallback(() => {
26
+ setExpanded(expanded => !expanded)
27
+ })
28
+
29
+ useEffect(() => {
30
+ function handleKeyDown(event: KeyboardEvent) {
31
+ if (event.code === 'KeyJ' && (event.ctrlKey || event.metaKey)) {
32
+ event.preventDefault()
33
+ event.stopPropagation()
34
+
35
+ if (expanded) {
36
+ setExpanded(false)
37
+ toggleButtonRef.current?.blur()
38
+ } else {
39
+ if (toggleButtonRef.current !== document.activeElement) {
40
+ toggleButtonRef.current?.focus()
41
+ } else {
42
+ toggleButtonRef.current?.blur()
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ document.addEventListener('keydown', handleKeyDown)
49
+ return () => document.removeEventListener('keydown', handleKeyDown)
50
+ }, [expanded, handleToggle])
51
+
52
+ const devBarContentRef = useRef<HTMLDivElement>(null)
53
+
54
+ useOnElementClickOutsideCallback(devBarContentRef, () => {
55
+ if (expanded) {
56
+ setExpanded(false)
57
+ toggleButtonRef.current?.blur()
58
+ }
59
+ })
60
+
61
+ const id = `dev-bar-panel${useId()}`
62
+
63
+ return (
64
+ <section
65
+ data-transparent
66
+ data-overrides-lucide-icons
67
+ data-expanded={dataAttribute(expanded)}
68
+ data-small-screen={dataAttribute(isSmallScreen)}
69
+ className={className(null)}
70
+ onKeyDown={event => {
71
+ if (event.code === 'Escape') {
72
+ event.preventDefault()
73
+ event.stopPropagation()
74
+
75
+ if (expanded) {
76
+ setExpanded(false)
77
+ } else if (document.activeElement && document.activeElement instanceof HTMLElement) {
78
+ document.activeElement.blur()
79
+ }
80
+ }
81
+ }}
82
+ >
83
+ <style>{`svg { pointer-events: none }`}</style>
84
+ <div ref={devBarContentRef} className={className('content')}>
85
+ <div
86
+ data-expanded={dataAttribute(expanded)}
87
+ id={id}
88
+ role="dialog"
89
+ style={{ display: 'contents' }}
90
+ >
91
+ <div className={className('brand')}>
92
+ {brand}
93
+
94
+ </div>
95
+
96
+ <div className={className('panels')}>
97
+ {children}
98
+ </div>
99
+
100
+ </div>
101
+
102
+ <button
103
+ ref={toggleButtonRef}
104
+ id="dev-bar-toggle-button"
105
+ aria-label="Toggle Contember Developer Toolbar"
106
+ aria-controls={id}
107
+ aria-expanded={expanded}
108
+ className={className('close')}
109
+ onClick={handleToggle}
110
+ tabIndex={0}
111
+ >
112
+ {expanded ? '🗙' : 'ᐸ'}
113
+ </button>
114
+ </div>
115
+ </section>
116
+ )
117
+ }
118
+
119
+ export const DevPanel = ({ heading, icon, children, preview }: {
120
+ icon: ReactNode;
121
+ heading: ReactNode,
122
+ children: ReactNode,
123
+ preview?: ReactNode
124
+ }) => {
125
+ const id = `cui-devBar-panel-${useId()}`
126
+ const className = useClassNameFactory('devBar')
127
+ const [expanded, setExpanded] = useState(false)
128
+ const mouseEnterTimeStampRef = useRef<ReturnType<typeof Date.now> | undefined>(undefined)
129
+
130
+ const devPanelRef = useRef<HTMLDivElement>(null)
131
+
132
+ useOnElementMouseEnterDelayedCallback(devPanelRef, useReferentiallyStableCallback(({ type }) => {
133
+ if (type === 'mouseenter') {
134
+ mouseEnterTimeStampRef.current = Date.now() + 300
135
+ setExpanded(true)
136
+ }
137
+ }))
138
+
139
+ return (
140
+ <div
141
+ ref={devPanelRef}
142
+ data-expanded={dataAttribute(expanded)}
143
+ className={className('trigger')}
144
+ onMouseLeave={useReferentiallyStableCallback(() => {
145
+ setExpanded(false)
146
+ })}
147
+ onKeyDown={useReferentiallyStableCallback(event => {
148
+ if (expanded && event.code === 'Escape') {
149
+ event.preventDefault()
150
+ event.stopPropagation()
151
+ setExpanded(false)
152
+ }
153
+ })}
154
+ >
155
+ <button
156
+ tabIndex={0}
157
+ aria-haspopup="dialog"
158
+ aria-controls={id}
159
+ aria-expanded={expanded}
160
+ className={className('trigger-label')}
161
+ onClick={useReferentiallyStableCallback(() => {
162
+ if (mouseEnterTimeStampRef.current && Date.now() < mouseEnterTimeStampRef.current) {
163
+ return
164
+ } else {
165
+ setExpanded(expanded => !expanded)
166
+ mouseEnterTimeStampRef.current = undefined
167
+ }
168
+ })}
169
+ >
170
+ {icon}
171
+ <span className={className('trigger-label-text')}>{preview ?? heading}</span>
172
+ </button>
173
+ {expanded && (
174
+ <div tabIndex={0} id={id} role="dialog" className={className('panel', 'dangerously-remove-native-focus-outline')}>
175
+ <div className={className('panel-content', 'native-focus-outline-handler')}>
176
+ <h2 className="h4">
177
+ {heading}
178
+ </h2>
179
+ <div className={className('panel-body')}>
180
+ {children}
181
+ </div>
182
+ </div>
183
+ </div>
184
+ )}
185
+ </div>
186
+ )
187
+ }
@@ -0,0 +1,171 @@
1
+ .cui-devBar {
2
+ align-items: center;
3
+ bottom: 0;
4
+ display: flex;
5
+ flex-direction: column;
6
+ position: fixed;
7
+ z-index: 1000;
8
+ left: 0;
9
+ right: 0;
10
+ opacity: 1;
11
+ padding: 1rem;
12
+ transition-property: opacity, transform;
13
+ transition-duration: 200ms;
14
+ transition-timing-function: ease-in-out;
15
+ }
16
+
17
+ .cui-devBar-content,
18
+ .cui-devBar-panel-content {
19
+ background: #eee;
20
+ color: #002251;
21
+ }
22
+
23
+ .cui-devBar-content {
24
+ align-self: center;
25
+ align-items: center;
26
+ border-radius: 1rem;
27
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
28
+ display: flex;
29
+ gap: 1rem;
30
+ padding: 0.5rem;
31
+ margin: 0 auto;
32
+ }
33
+
34
+
35
+ .cui-devBar-close,
36
+ .cui-devBar-trigger-label,
37
+ .cui-devBar-brand {
38
+ align-items: center;
39
+ height: 2rem;
40
+ border-radius: 0.5rem;
41
+ justify-content: center;
42
+ max-height: 2rem;
43
+ min-height: 2rem;
44
+ white-space: nowrap;
45
+ }
46
+
47
+ .cui-devBar-close {
48
+ background: transparent;
49
+ cursor: pointer;
50
+ display: flex;
51
+ max-width: 2rem;
52
+ width: 2rem;
53
+ order: 999;
54
+ }
55
+
56
+
57
+ .cui-devBar-brand {
58
+ align-items: center;
59
+ display: flex;
60
+ gap: 1rem;
61
+ text-align: right;
62
+ }
63
+ .cui-devBar-brand svg {
64
+ max-height: 2rem;
65
+ }
66
+
67
+
68
+ .cui-devBar-panels {
69
+ display: flex;
70
+ gap: 1rem;
71
+ }
72
+
73
+ .cui-devBar-trigger {
74
+ display: flex;
75
+ }
76
+
77
+ .cui-devBar-trigger-label {
78
+ align-items: center;
79
+ color: inherit;
80
+ cursor: pointer;
81
+ display: inline-flex;
82
+ font-weight: normal;
83
+ gap: 0.3rem;
84
+ padding: 0 0.2rem;
85
+ }
86
+
87
+ .cui-devBar-trigger-label:hover {
88
+ background-color: #e0e0e0;
89
+ }
90
+
91
+
92
+ .cui-devBar-panel {
93
+ justify-content: center;
94
+ display: flex;
95
+ flex-direction: row;
96
+ gap: 1rem;
97
+ left: 0;
98
+ position: absolute;
99
+ right: 0;
100
+ bottom: 0;
101
+ padding: 2rem;
102
+ transform: translateY(-1rem);
103
+ }
104
+
105
+ .cui-devBar-trigger:not([data-expanded]) > .cui-devBar-panel {
106
+ display: none;
107
+ }
108
+
109
+ .cui-devBar-panel-content {
110
+ background: #fff;
111
+ border: 1px solid #ccc;
112
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
113
+ border-radius: 0.5rem;
114
+ display: flex;
115
+ min-width: min(20rem, 100%);
116
+ max-width: 100%;
117
+ flex-direction: column;
118
+ flex-shrink: 1;
119
+ }
120
+ .cui-devBar-panel-content h2 {
121
+ font-weight: bold;
122
+ margin-bottom: 0;
123
+ padding: 0.4rem 1rem;
124
+ border-radius: 0.5rem 0.5rem 0 0;
125
+ background: #f8f8f8;
126
+ }
127
+
128
+ @media screen and (min-width: 768px) {
129
+ .cui-devBar-trigger {
130
+ position: relative;
131
+ }
132
+
133
+ .cui-devBar-panel-content {
134
+ min-width: unset;
135
+ max-width: unset;
136
+ }
137
+
138
+ .cui-devBar-panel-body {
139
+ min-width: 20rem;
140
+ }
141
+ }
142
+
143
+ .cui-devBar-panel-body {
144
+ border-top: 1px solid #ccc;
145
+ display: flex;
146
+ flex-direction: column;
147
+ gap: 1rem;
148
+ padding: 1rem;
149
+ }
150
+
151
+ .cui-devBar:not([data-expanded]) {
152
+ transform: translateY(2rem);
153
+ opacity: 0;
154
+ max-width: 5rem;
155
+ margin: auto;
156
+ }
157
+
158
+
159
+ .cui-devBar:not([data-expanded]):hover,
160
+ .cui-devBar:not([data-expanded]):focus-within {
161
+ transform: unset;
162
+ opacity: unset;
163
+ }
164
+
165
+ [id^="dev-bar-panel"]:not([data-expanded]) > * {
166
+ display: none;
167
+ }
168
+
169
+ .cui-devBar-panel .cui-table-wrapper {
170
+ overflow: auto;
171
+ }
@@ -0,0 +1 @@
1
+ export * from './DevBar'
@@ -0,0 +1,191 @@
1
+ .cui-devError {
2
+ position: absolute;
3
+ top: 0;
4
+ right: 0;
5
+ bottom: 0;
6
+ left: 0;
7
+ width: 100vw;
8
+ height: 100vh;
9
+ z-index: 99;
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: flex-start;
13
+ background: rgba(212, 212, 212, 0.66);
14
+ font-family: Poppins, Roboto, sans-serif;
15
+ }
16
+
17
+ .cui-devError-in {
18
+ z-index: 100;
19
+ width: 100%;
20
+ height: 100%;
21
+ color: #333;
22
+ background: #222;
23
+ box-shadow: 3px 3px 10px rgba(50, 50, 50, 0.5);
24
+ display: flex;
25
+ flex-direction: column;
26
+ overflow: auto;
27
+ }
28
+
29
+ .cui-devError-header {
30
+ background: #CD1818;
31
+ color: #FFF;
32
+ padding: 0.5em 1em;
33
+ }
34
+
35
+ .cui-devError-errorMessage,
36
+ .cui-devError-errorName,
37
+ .cui-devError-errorDetails {
38
+ margin: 0;
39
+ flex: 0 0 auto;
40
+ font-weight: 300;
41
+ white-space: pre-wrap;
42
+ overflow-wrap: break-word;
43
+ line-height: 130%;
44
+ }
45
+
46
+ .cui-devError-errorMessage {
47
+ font-family: monospace;
48
+ margin-top: 0.5em;
49
+ font-size: 1.7em;
50
+ }
51
+
52
+ .cui-devError-errorDetails {
53
+ font-family: monospace;
54
+ margin-top: 0.5em;
55
+ font-size: 1em;
56
+ white-space: pre;
57
+ overflow-x: scroll;
58
+ }
59
+
60
+ .cui-devError-causeLink {
61
+ color: #FFCC00;
62
+ text-decoration: underline;
63
+ }
64
+
65
+ .cui-devError-stack {
66
+ flex: 1 1 auto;
67
+ }
68
+
69
+ .cui-devError-stack-dump {
70
+ color: #fff;
71
+ margin-top: 1em;
72
+ padding: 1em;
73
+ white-space: pre-wrap;
74
+ }
75
+
76
+ .cui-devError-bar {
77
+ padding: 0.2em 0.2em 0.2em 1em;
78
+ background: #ac1616;
79
+ color: #eee;
80
+ display: flex;
81
+ }
82
+
83
+ .cui-devError-causedBy {
84
+ padding: 0.2em 0.2em 0.2em 1em;
85
+ background: #FFCC00;
86
+ color: #000;
87
+ display: flex;
88
+ }
89
+
90
+ .cui-devError-actions {
91
+ margin-left: auto;
92
+ display: flex;
93
+ }
94
+
95
+ .cui-devError-actions .cui-button {
96
+ color: #fff;
97
+ border-color: #cbcbcb;
98
+ }
99
+
100
+ .cui-devError-actions .cui-button:hover {
101
+ color: #fff;
102
+ }
103
+
104
+ .cui-devError-close {
105
+ margin-left: 1em;
106
+ }
107
+
108
+ .cui-devError-close .cui-button {
109
+ border-color: transparent;
110
+ }
111
+
112
+ .cui-devError-switcher {
113
+ display: flex;
114
+ align-items: center;
115
+ margin-left: 2em;
116
+ }
117
+
118
+
119
+ .cui-devError-switcherButtons {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 0.5em;
123
+ }
124
+ .cui-devError-closeButton,
125
+ .cui-devError-switcherButton {
126
+ border: 1px solid #cbcbcb;
127
+ border-radius: 0.2em;
128
+ padding: 0.2em 0.5em;
129
+ }
130
+
131
+ .cui-devError-errorCount {
132
+ margin: 0;
133
+ margin-right: 0.5em;
134
+ }
135
+
136
+ .cui-devError-stackFrame {
137
+ font-family: monospace;
138
+ }
139
+
140
+ .cui-devError-stackFrame:last-child {
141
+ border-bottom: 1px solid #666;
142
+ }
143
+
144
+ .cui-devError-stackFrameHeader {
145
+ display: flex;
146
+ padding: 0.5em 1em;
147
+ background: #333;
148
+ color: #fff;
149
+ border-bottom: 1px solid #666;
150
+ border-top: 1px solid #666;
151
+ }
152
+
153
+ .cui-devError-stackFrameSource {
154
+ margin-left: 0.2em;
155
+ }
156
+
157
+ .cui-devError-stackFrameCallee {
158
+ margin-left: 1em;
159
+ color: #a4ffa4;
160
+ }
161
+
162
+ .cui-devError-stackFrameCode {
163
+ background: #222;
164
+ color: #D5D5D5;
165
+ }
166
+
167
+ .cui-devError-stackFrameLine {
168
+ display: flex;
169
+ }
170
+
171
+ .cui-devError-stackFrameLine.is-active {
172
+ color: #fff;
173
+ background: #CD1818;
174
+ }
175
+
176
+ .cui-devError-stackFrameLine.is-active .cui-devError-stackFrameLineNumber {
177
+ color: #fff;
178
+ }
179
+
180
+ .cui-devError-stackFrameLineNumber {
181
+ color: #888;
182
+ flex: 0 0 50px;
183
+ text-align: right;
184
+ padding: 0.2em;
185
+ }
186
+
187
+ .cui-devError-stackFrameLineCode {
188
+ padding: 0.2em 1em;
189
+ white-space: pre-wrap;
190
+ tab-size: 4;
191
+ }
@@ -0,0 +1,21 @@
1
+ import { useClassNameFactory } from '@contember/react-utils'
2
+ import { DevErrorInner, DevErrorInnerProps } from './DevErrorInner'
3
+
4
+ export interface DevErrorProps extends DevErrorInnerProps {
5
+ source: string
6
+ }
7
+
8
+ export function DevError(props: DevErrorProps) {
9
+ const componentClassName = useClassNameFactory('devError')
10
+
11
+ return (
12
+ <div className={componentClassName()}>
13
+ <div className={componentClassName('in')}>
14
+ <div className={componentClassName('bar')}>
15
+ <div className={componentClassName('errorSource')}>{props.source}</div>
16
+ </div>
17
+ <DevErrorInner error={props.error} />
18
+ </div>
19
+ </div>
20
+ )
21
+ }
@@ -0,0 +1,16 @@
1
+ :where(.cui-devErrorBadge) {
2
+ position: fixed;
3
+ bottom: 20px;
4
+ left: 20px;
5
+ }
6
+
7
+ :where(.cui-devErrorBadge-button) {
8
+ display: block;
9
+ background: #CD1818;
10
+ color: #fff;
11
+ font-weight: 600;
12
+ box-shadow: 3px 3px 7px rgba(50, 50, 50, 0.5);
13
+ border-radius: 10px;
14
+ padding: 1em 2em;
15
+ cursor: pointer;
16
+ }
@@ -0,0 +1,18 @@
1
+ import { useClassNameFactory } from '@contember/react-utils'
2
+
3
+ export interface DevErrorBadgeProps {
4
+ onOpen: () => void
5
+ errorCount: number
6
+ }
7
+
8
+ export function DevErrorBadge({ errorCount, onOpen }: DevErrorBadgeProps) {
9
+ const componentClassName = useClassNameFactory('devErrorBadge')
10
+
11
+ return (
12
+ <div className={componentClassName()}>
13
+ <a className={componentClassName('button')} onClick={onOpen}>
14
+ {errorCount} {errorCount > 1 ? 'errors' : 'error'}
15
+ </a>
16
+ </div>
17
+ )
18
+ }
@@ -0,0 +1,46 @@
1
+ import { useClassNameFactory } from '@contember/react-utils'
2
+ import { StackTrace } from './StackTrace'
3
+ import type { ProcessedError } from './types'
4
+
5
+ export interface DevErrorInnerProps {
6
+ error: ProcessedError
7
+ level?: number
8
+ }
9
+
10
+ export function DevErrorInner({ error, level = 1 }: DevErrorInnerProps) {
11
+ const componentClassName = useClassNameFactory('devError')
12
+
13
+ let errorObject: Error | undefined = error.error instanceof Error ? error.error : undefined
14
+
15
+ return (
16
+ <>
17
+ <div className={componentClassName('header')}>
18
+ {errorObject ? (
19
+ <>
20
+ <h1 className={componentClassName('errorName')}>{errorObject.name}</h1>
21
+ {error.cause && <a href={`#error-${level}`} className={componentClassName('causeLink')}>caused by &gt;</a>}
22
+ {errorObject.message && <h2 className={componentClassName('errorMessage')}>{errorObject.message}</h2>}
23
+ {'details' in errorObject && <h3 className={componentClassName('errorDetails')}>{(errorObject as any).details}</h3>}
24
+ </>
25
+ ) : (
26
+ <h1 className={componentClassName('errorName')}>Unknown error</h1>
27
+ )}
28
+ </div>
29
+ {error.parsedStackStrace ? (
30
+ <StackTrace stackTrace={error.parsedStackStrace} />
31
+ ) : errorObject?.stack ? (
32
+ <div className={componentClassName('stack')}>
33
+ <div className={componentClassName('stack-dump')}>{errorObject.stack}</div>
34
+ </div>
35
+ ) : null}
36
+ {error.cause ? (
37
+ <>
38
+ <div className={componentClassName('causedBy')} id={`error-${level}`}>
39
+ Caused by
40
+ </div>
41
+ <DevErrorInner error={error.cause} level={level + 1} />
42
+ </>
43
+ ) : null}
44
+ </>
45
+ )
46
+ }
@@ -0,0 +1,60 @@
1
+ import { useClassNameFactory } from '@contember/react-utils'
2
+ import { DevErrorInner } from './DevErrorInner'
3
+ import { ProcessedError } from './types'
4
+
5
+ export interface DevErrorListProps {
6
+ currentError: ProcessedError
7
+ currentErrorSource: string
8
+ currentErrorIndex: number
9
+ errorCount: number
10
+ onPrevious: () => void
11
+ onNext: () => void
12
+ onClose: () => void
13
+ }
14
+
15
+
16
+ export function DevErrorList({
17
+ currentError,
18
+ currentErrorIndex,
19
+ currentErrorSource,
20
+ errorCount,
21
+ onClose,
22
+ onNext,
23
+ onPrevious,
24
+ }: DevErrorListProps) {
25
+ const componentClassName = useClassNameFactory('devError')
26
+
27
+ return (
28
+ <div className={componentClassName()}>
29
+ <div className={componentClassName('in')}>
30
+ <div className={componentClassName('bar')}>
31
+ <div className={componentClassName('errorSource')}>{currentErrorSource}</div>
32
+ <div className={componentClassName('actions')}>
33
+ {errorCount > 1 ? (
34
+ <div className={componentClassName('switcher')}>
35
+ <p className={componentClassName('errorCount')}>
36
+ Error {currentErrorIndex + 1} of {errorCount}
37
+ </p>
38
+ <div className={componentClassName('switcherButtons')}>
39
+ <button className={componentClassName('switcherButton')} onClick={onPrevious}>
40
+ ᐊ
41
+ </button>
42
+ <button className={componentClassName('switcherButton')} onClick={onNext}>
43
+ ᐅ
44
+ </button>
45
+ </div>
46
+ </div>
47
+ ) : null}
48
+ <div className={componentClassName('close')}>
49
+ <button className={componentClassName('closeButton')} onClick={onClose}>
50
+ 🗙
51
+ </button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <DevErrorInner error={currentError} />
57
+ </div>
58
+ </div>
59
+ )
60
+ }