@contember/react-devbar 2.0.0-alpha.8 → 2.0.0-beta.1

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 (64) hide show
  1. package/dist/development/src/DevErrorManager.cjs.map +1 -1
  2. package/dist/development/src/DevErrorManager.js.map +1 -1
  3. package/dist/development/src/errorHandling.cjs.map +1 -1
  4. package/dist/development/src/errorHandling.js.map +1 -1
  5. package/dist/development/src/hooks/useParsedStacktrace.cjs +6 -1
  6. package/dist/development/src/hooks/useParsedStacktrace.cjs.map +1 -1
  7. package/dist/development/src/hooks/useParsedStacktrace.js +6 -1
  8. package/dist/development/src/hooks/useParsedStacktrace.js.map +1 -1
  9. package/dist/development/src/ui/DevBar/DevBar.cjs +128 -174
  10. package/dist/development/src/ui/DevBar/DevBar.cjs.map +1 -1
  11. package/dist/development/src/ui/DevBar/DevBar.js +130 -176
  12. package/dist/development/src/ui/DevBar/DevBar.js.map +1 -1
  13. package/dist/development/src/ui/DevError/DevError.cjs +5 -5
  14. package/dist/development/src/ui/DevError/DevError.cjs.map +1 -1
  15. package/dist/development/src/ui/DevError/DevError.js +5 -5
  16. package/dist/development/src/ui/DevError/DevError.js.map +1 -1
  17. package/dist/development/src/ui/DevError/DevErrorInner.cjs +1 -1
  18. package/dist/development/src/ui/DevError/DevErrorInner.cjs.map +1 -1
  19. package/dist/development/src/ui/DevError/DevErrorInner.js +1 -1
  20. package/dist/development/src/ui/DevError/DevErrorInner.js.map +1 -1
  21. package/dist/development/src/ui/DevError/DevErrorList.cjs +28 -17
  22. package/dist/development/src/ui/DevError/DevErrorList.cjs.map +1 -1
  23. package/dist/development/src/ui/DevError/DevErrorList.js +28 -17
  24. package/dist/development/src/ui/DevError/DevErrorList.js.map +1 -1
  25. package/dist/development/src/ui/DevError/StackTrace.cjs.map +1 -1
  26. package/dist/development/src/ui/DevError/StackTrace.js.map +1 -1
  27. package/dist/production/src/errorHandling.cjs.map +1 -1
  28. package/dist/production/src/errorHandling.js.map +1 -1
  29. package/dist/production/src/hooks/useParsedStacktrace.cjs +6 -1
  30. package/dist/production/src/hooks/useParsedStacktrace.cjs.map +1 -1
  31. package/dist/production/src/hooks/useParsedStacktrace.js +6 -1
  32. package/dist/production/src/hooks/useParsedStacktrace.js.map +1 -1
  33. package/dist/production/src/ui/DevBar/DevBar.cjs +74 -112
  34. package/dist/production/src/ui/DevBar/DevBar.cjs.map +1 -1
  35. package/dist/production/src/ui/DevBar/DevBar.js +77 -115
  36. package/dist/production/src/ui/DevBar/DevBar.js.map +1 -1
  37. package/dist/production/src/ui/DevError/DevError.cjs.map +1 -1
  38. package/dist/production/src/ui/DevError/DevError.js.map +1 -1
  39. package/dist/production/src/ui/DevError/DevErrorBadge.cjs.map +1 -1
  40. package/dist/production/src/ui/DevError/DevErrorBadge.js.map +1 -1
  41. package/dist/production/src/ui/DevError/DevErrorInner.cjs +1 -1
  42. package/dist/production/src/ui/DevError/DevErrorInner.cjs.map +1 -1
  43. package/dist/production/src/ui/DevError/DevErrorInner.js +1 -1
  44. package/dist/production/src/ui/DevError/DevErrorInner.js.map +1 -1
  45. package/dist/production/src/ui/DevError/DevErrorList.cjs +11 -4
  46. package/dist/production/src/ui/DevError/DevErrorList.cjs.map +1 -1
  47. package/dist/production/src/ui/DevError/DevErrorList.js +11 -4
  48. package/dist/production/src/ui/DevError/DevErrorList.js.map +1 -1
  49. package/dist/production/src/ui/DevError/StackTrace.cjs.map +1 -1
  50. package/dist/production/src/ui/DevError/StackTrace.js.map +1 -1
  51. package/dist/types/hooks/useParsedStacktrace.d.ts +1 -1
  52. package/dist/types/hooks/useParsedStacktrace.d.ts.map +1 -1
  53. package/dist/types/tsconfig.tsbuildinfo +1 -1
  54. package/dist/types/ui/DevBar/DevBar.d.ts +5 -4
  55. package/dist/types/ui/DevBar/DevBar.d.ts.map +1 -1
  56. package/dist/types/ui/DevError/DevError.d.ts.map +1 -1
  57. package/dist/types/ui/DevError/DevErrorList.d.ts.map +1 -1
  58. package/package.json +7 -6
  59. package/src/hooks/useParsedStacktrace.ts +6 -1
  60. package/src/index.css +290 -227
  61. package/src/ui/DevBar/DevBar.tsx +72 -97
  62. package/src/ui/DevError/DevError.tsx +0 -1
  63. package/src/ui/DevError/DevErrorInner.tsx +1 -1
  64. package/src/ui/DevError/DevErrorList.tsx +14 -5
@@ -1,26 +1,22 @@
1
1
  import {
2
2
  useId,
3
3
  useOnElementClickOutsideCallback,
4
- useOnElementMouseEnterDelayedCallback,
5
4
  useReferentiallyStableCallback,
6
5
  useWindowSize,
7
6
  } from '@contember/react-utils'
8
7
  import { dataAttribute } from '@contember/utilities'
9
- import { PropsWithChildren, ReactNode, useEffect, useRef, useState } from 'react'
8
+ import { PropsWithChildren, ReactNode, useCallback, useEffect, useRef, useState } from 'react'
10
9
 
11
10
  const className = (cls: string | null) => cls ? `cui-devBar-${cls}` : 'cui-devBar'
12
11
 
13
12
  export const DevBar = ({
14
13
  breakpoint = 768,
15
14
  children,
16
- brand,
17
15
  }: PropsWithChildren<{
18
- brand?: ReactNode
19
16
  breakpoint?: number
20
17
  }>) => {
21
- const [expanded, setExpanded] = useState(true)
18
+ const [expanded, setExpanded] = useState(false)
22
19
  const isSmallScreen = useWindowSize().width < breakpoint
23
- const toggleButtonRef = useRef<HTMLButtonElement>(null)
24
20
 
25
21
  const handleToggle = useReferentiallyStableCallback(() => {
26
22
  setExpanded(expanded => !expanded)
@@ -32,16 +28,7 @@ export const DevBar = ({
32
28
  event.preventDefault()
33
29
  event.stopPropagation()
34
30
 
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
- }
31
+ handleToggle()
45
32
  }
46
33
  }
47
34
 
@@ -54,7 +41,6 @@ export const DevBar = ({
54
41
  useOnElementClickOutsideCallback(devBarContentRef, () => {
55
42
  if (expanded) {
56
43
  setExpanded(false)
57
- toggleButtonRef.current?.blur()
58
44
  }
59
45
  })
60
46
 
@@ -62,125 +48,114 @@ export const DevBar = ({
62
48
 
63
49
  return (
64
50
  <section
65
- data-transparent
66
- data-overrides-lucide-icons
51
+ data-transparent="true"
52
+ data-overrides-lucide-icons="true"
67
53
  data-expanded={dataAttribute(expanded)}
68
54
  data-small-screen={dataAttribute(isSmallScreen)}
69
55
  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
56
  >
83
- <style>{`svg { pointer-events: none }`}</style>
84
57
  <div ref={devBarContentRef} className={className('content')}>
85
58
  <div
86
- data-expanded={dataAttribute(expanded)}
59
+ data-expanded={true}
87
60
  id={id}
88
61
  role="dialog"
89
62
  style={{ display: 'contents' }}
90
63
  >
91
- <div className={className('brand')}>
92
- {brand}
93
-
94
- </div>
95
-
96
64
  <div className={className('panels')}>
97
65
  {children}
98
66
  </div>
99
-
100
67
  </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
68
  </div>
115
69
  </section>
116
70
  )
117
71
  }
118
72
 
119
- export const DevPanel = ({ heading, icon, children, preview }: {
73
+ interface DevPanelProps {
120
74
  icon: ReactNode
121
75
  heading: ReactNode
122
76
  children: ReactNode
123
77
  preview?: ReactNode
124
- }) => {
78
+ }
79
+
80
+ export const DevPanel = ({ heading, icon, children, preview }: DevPanelProps) => {
125
81
  const id = `cui-devBar-panel-${useId()}`
126
- const [expanded, setExpanded] = useState(false)
127
- const mouseEnterTimeStampRef = useRef<ReturnType<typeof Date.now> | undefined>(undefined)
82
+ const dialogRef = useRef<HTMLDialogElement>(null)
83
+ const triggerRef = useRef<HTMLButtonElement>(null)
84
+
85
+ const handleOpen = useCallback(() => {
86
+ dialogRef.current?.showModal()
87
+ }, [])
88
+
89
+ const handleClose = useCallback(() => {
90
+ dialogRef.current?.close()
91
+ }, [])
128
92
 
129
- const devPanelRef = useRef<HTMLDivElement>(null)
93
+ useEffect(() => {
94
+ const dialog = dialogRef.current
95
+ if (!dialog) return
96
+
97
+ const handleClickOutside = (event: MouseEvent) => {
98
+ const rect = dialog.getBoundingClientRect()
99
+ const isInDialog = (
100
+ rect.top <= event.clientY &&
101
+ event.clientY <= rect.top + rect.height &&
102
+ rect.left <= event.clientX &&
103
+ event.clientX <= rect.left + rect.width
104
+ )
105
+
106
+ if (!isInDialog) {
107
+ dialog.close()
108
+ }
109
+ }
130
110
 
131
- useOnElementMouseEnterDelayedCallback(devPanelRef, useReferentiallyStableCallback(({ type }) => {
132
- if (type === 'mouseenter') {
133
- mouseEnterTimeStampRef.current = Date.now() + 300
134
- setExpanded(true)
111
+ dialog.addEventListener('click', handleClickOutside)
112
+ return () => dialog.removeEventListener('click', handleClickOutside)
113
+ }, [])
114
+
115
+ useEffect(() => {
116
+ const handleEscape = (event: KeyboardEvent) => {
117
+ if (event.key === 'Escape') {
118
+ handleClose()
119
+ }
135
120
  }
136
- }))
121
+
122
+ document.addEventListener('keydown', handleEscape)
123
+ return () => document.removeEventListener('keydown', handleEscape)
124
+ }, [handleClose])
137
125
 
138
126
  return (
139
- <div
140
- ref={devPanelRef}
141
- data-expanded={dataAttribute(expanded)}
142
- className={className('trigger')}
143
- onMouseLeave={useReferentiallyStableCallback(() => {
144
- setExpanded(false)
145
- })}
146
- onKeyDown={useReferentiallyStableCallback(event => {
147
- if (expanded && event.code === 'Escape') {
148
- event.preventDefault()
149
- event.stopPropagation()
150
- setExpanded(false)
151
- }
152
- })}
153
- >
127
+ <div className={className('trigger')}>
154
128
  <button
129
+ ref={triggerRef}
155
130
  tabIndex={0}
156
131
  aria-haspopup="dialog"
157
132
  aria-controls={id}
158
- aria-expanded={expanded}
159
133
  className={className('trigger-label')}
160
- onClick={useReferentiallyStableCallback(() => {
161
- if (mouseEnterTimeStampRef.current && Date.now() < mouseEnterTimeStampRef.current) {
162
- return
163
- } else {
164
- setExpanded(expanded => !expanded)
165
- mouseEnterTimeStampRef.current = undefined
166
- }
167
- })}
134
+ onClick={handleOpen}
168
135
  >
169
136
  {icon}
170
- <span className={className('trigger-label-text')}>{preview ?? heading}</span>
137
+ <span className={className('trigger-label-text')}>
138
+ {preview ?? heading}
139
+ </span>
171
140
  </button>
172
- {expanded && (
173
- <div tabIndex={0} id={id} role="dialog" className={className('panel')}>
174
- <div className={className('panel-content')}>
175
- <h2 className="h4">
176
- {heading}
177
- </h2>
178
- <div className={className('panel-body')}>
179
- {children}
180
- </div>
141
+
142
+ <dialog ref={dialogRef} id={id} className={className('panel')}>
143
+ <div className={className('panel-content')}>
144
+ <div className={className('panel-header')}>
145
+ <h2 className="h4">{heading}</h2>
146
+ <button
147
+ onClick={handleClose}
148
+ className={className('close-button')}
149
+ aria-label="Close"
150
+ >
151
+ ✕
152
+ </button>
153
+ </div>
154
+ <div className={className('panel-body')}>
155
+ {children}
181
156
  </div>
182
157
  </div>
183
- )}
158
+ </dialog>
184
159
  </div>
185
160
  )
186
161
  }
@@ -7,7 +7,6 @@ export interface DevErrorProps extends DevErrorInnerProps {
7
7
  const className = (cls?: string | null) => cls ? `cui-devError-${cls}` : 'cui-devError'
8
8
 
9
9
  export function DevError(props: DevErrorProps) {
10
-
11
10
  return (
12
11
  <div className={className()}>
13
12
  <div className={className('in')}>
@@ -21,7 +21,7 @@ export function DevErrorInner({ error, level = 1 }: DevErrorInnerProps) {
21
21
  <h1 className={className('errorName')}>{errorObject.name}</h1>
22
22
  {error.cause && <a href={`#error-${level}`} className={className('causeLink')}>caused by &gt;</a>}
23
23
  {errorObject.message && <h2 className={className('errorMessage')}>{errorObject.message}</h2>}
24
- {'details' in errorObject && <h3 className={className('errorDetails')}>{(errorObject as any).details}</h3>}
24
+ {'details' in errorObject && <div className={className('errorDetails')}>{(errorObject as any).details}</div>}
25
25
  </>
26
26
  ) : (
27
27
  <h1 className={className('errorName')}>Unknown error</h1>
@@ -1,5 +1,6 @@
1
1
  import { DevErrorInner } from './DevErrorInner'
2
2
  import { ProcessedError } from './types'
3
+ import { useEffect } from 'react'
3
4
 
4
5
  export interface DevErrorListProps {
5
6
  currentError: ProcessedError
@@ -22,6 +23,13 @@ export function DevErrorList({
22
23
  onNext,
23
24
  onPrevious,
24
25
  }: DevErrorListProps) {
26
+ useEffect(() => {
27
+ document.body.classList.add('cui-devError-body')
28
+ return () => {
29
+ document.body.classList.remove('cui-devError-body')
30
+ }
31
+ }, [])
32
+
25
33
  return (
26
34
  <div className={className()}>
27
35
  <div className={className('in')}>
@@ -35,23 +43,24 @@ export function DevErrorList({
35
43
  </p>
36
44
  <div className={className('switcherButtons')}>
37
45
  <button className={className('switcherButton')} onClick={onPrevious}>
38
- ᐊ
46
+ ←
39
47
  </button>
40
48
  <button className={className('switcherButton')} onClick={onNext}>
41
- ᐅ
49
+ →
42
50
  </button>
43
51
  </div>
44
52
  </div>
45
53
  ) : null}
46
54
  <div className={className('close')}>
47
55
  <button className={className('closeButton')} onClick={onClose}>
48
- 🗙
56
+ ✕
49
57
  </button>
50
58
  </div>
51
59
  </div>
52
60
  </div>
53
-
54
- <DevErrorInner error={currentError} />
61
+ <div className={className('content')}>
62
+ <DevErrorInner error={currentError} />
63
+ </div>
55
64
  </div>
56
65
  </div>
57
66
  )