@stack-spot/portal-layout 0.0.33 → 0.0.35

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 (39) hide show
  1. package/dist/Layout.d.ts +1 -2
  2. package/dist/Layout.d.ts.map +1 -1
  3. package/dist/Layout.js +7 -5
  4. package/dist/Layout.js.map +1 -1
  5. package/dist/LayoutOverlayManager.js.map +1 -1
  6. package/dist/components/SelectionList.d.ts.map +1 -1
  7. package/dist/components/SelectionList.js +22 -2
  8. package/dist/components/SelectionList.js.map +1 -1
  9. package/dist/components/menu/MenuContent.d.ts +2 -545
  10. package/dist/components/menu/MenuContent.d.ts.map +1 -1
  11. package/dist/components/menu/MenuContent.js.map +1 -1
  12. package/dist/components/menu/MenuSections.d.ts.map +1 -1
  13. package/dist/components/menu/MenuSections.js +43 -33
  14. package/dist/components/menu/MenuSections.js.map +1 -1
  15. package/dist/components/menu/PageSelector.js.map +1 -1
  16. package/dist/components/menu/types.d.ts +0 -1
  17. package/dist/components/menu/types.d.ts.map +1 -1
  18. package/dist/components/menu/use-check-text-overflow.js.map +1 -1
  19. package/dist/components/menu/use-keyboard-controls.d.ts +16 -3
  20. package/dist/components/menu/use-keyboard-controls.d.ts.map +1 -1
  21. package/dist/components/menu/use-keyboard-controls.js +21 -46
  22. package/dist/components/menu/use-keyboard-controls.js.map +1 -1
  23. package/dist/layout.css +24 -27
  24. package/dist/utils.js.map +1 -1
  25. package/package.json +5 -5
  26. package/src/Layout.tsx +7 -6
  27. package/src/components/SelectionList.tsx +24 -2
  28. package/src/components/menu/MenuSections.tsx +49 -37
  29. package/src/components/menu/types.ts +0 -1
  30. package/src/components/menu/use-keyboard-controls.tsx +32 -50
  31. package/src/layout.css +24 -27
  32. package/dist/components/error/ErrorDescriptor.d.ts +0 -12
  33. package/dist/components/error/ErrorDescriptor.d.ts.map +0 -1
  34. package/dist/components/error/ErrorDescriptor.js +0 -17
  35. package/dist/components/error/ErrorDescriptor.js.map +0 -1
  36. package/dist/components/menu/useCheckTextOverflow.d.ts +0 -6
  37. package/dist/components/menu/useCheckTextOverflow.d.ts.map +0 -1
  38. package/dist/components/menu/useCheckTextOverflow.js +0 -20
  39. package/dist/components/menu/useCheckTextOverflow.js.map +0 -1
@@ -3,7 +3,7 @@ import { ArrowLeft, Check, ChevronRight } from '@citric/icons'
3
3
  import { IconButton } from '@citric/ui'
4
4
  import { WithStyle, listToClass, theme } from '@stack-spot/portal-theme'
5
5
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
6
- import { ReactElement, useMemo, useState } from 'react'
6
+ import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
7
7
  import { styled } from 'styled-components'
8
8
  import { useKeyboardControls } from './menu/use-keyboard-controls'
9
9
  import { Action } from './types'
@@ -174,6 +174,9 @@ export const SelectionList = ({
174
174
  }: SelectionListProps) => {
175
175
  const t = useTranslate(dictionary)
176
176
  const [current, setCurrent] = useState<CurrentItemList>({ items })
177
+ const { keyboardControlledElement: wrapper, attachKeyboardListeners, detachKeyboardListeners } = useKeyboardControls(
178
+ { onPressEscape: onHide, querySelectors: 'li.action a, li.collapsible a, button' },
179
+ )
177
180
 
178
181
  const listItems = useMemo(
179
182
  () => current.items.map(i => renderItem(
@@ -186,7 +189,26 @@ export const SelectionList = ({
186
189
  )),
187
190
  [current],
188
191
  )
189
- const wrapper = useKeyboardControls({ onHide, querySelectors: 'li.action a, li.collapsible a, button', visible })
192
+
193
+ const hide = useCallback((event: Event) => {
194
+ const target = (event.target as HTMLElement | null)
195
+ // if the element is not in the DOM anymore, we'll consider the click was inside the selection list
196
+ const isClickInsideSelectionList = !target?.isConnected || wrapper.current?.contains(target)
197
+ const isAction = target?.classList?.contains('action') || !!target?.closest('.action')
198
+ if (!isClickInsideSelectionList || isAction) onHide?.()
199
+ }, [])
200
+
201
+ useEffect(() => {
202
+ if (visible) {
203
+ setCurrent({ items })
204
+ attachKeyboardListeners()
205
+ if (onHide) setTimeout(() => document.addEventListener('click', hide), 50)
206
+ }
207
+ else {
208
+ detachKeyboardListeners()
209
+ document.removeEventListener('click', hide)
210
+ }
211
+ }, [visible])
190
212
 
191
213
  return (
192
214
  <SelectionBox
@@ -2,24 +2,38 @@ import { Flex, IconBox, Text } from '@citric/core'
2
2
  import { ChevronRight, Cog, Collapse, Expand } from '@citric/icons'
3
3
  import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
4
4
  import { useCallback, useMemo, useState } from 'react'
5
+ import { getLayoutElements } from '../../elements'
6
+ import { elementIds } from '../../elements'
5
7
  import { MenuContent } from './MenuContent'
6
8
  import { MenuProps, MenuSection } from './types'
7
9
  import { useKeyboardControls } from './use-keyboard-controls'
8
10
 
9
- const ARROW_HEIGHT = 24
10
11
  const HIDE_OVERLAY_DELAY_MS = 400
11
12
  const MENU_OVERLAY_ID = 'menuContentOverlay'
12
13
 
13
14
  let hideOverlayTask: number | undefined
14
15
 
16
+ // fixme: this should definitely not be handled like this...
17
+ let attachKeyboardListenersForOverlay: () => void
18
+ let detachKeyboardListenersForOverlay: () => void
19
+
15
20
  function hideOverlay() {
16
21
  if (hideOverlayTask !== undefined) return
17
22
  hideOverlayTask = window.setTimeout(hideOverlayImmediately, HIDE_OVERLAY_DELAY_MS)
18
23
  }
19
24
 
25
+ function getAccessibilityButtonOfSectionWithActiveOverlay(): HTMLElement | null | undefined {
26
+ return document.getElementById(elementIds.menuSections)?.querySelector('button[aria-expanded="true"]')
27
+ }
28
+
20
29
  // eslint-disable-next-line react-refresh/only-export-components
21
30
  export function hideOverlayImmediately() {
22
- document.getElementById(MENU_OVERLAY_ID)?.classList.remove('visible')
31
+ detachKeyboardListenersForOverlay?.()
32
+ const overlay = document.getElementById(MENU_OVERLAY_ID)
33
+ overlay?.setAttribute('inert', '')
34
+ overlay?.setAttribute('aria-hidden', '')
35
+ overlay?.classList.remove('visible')
36
+ getAccessibilityButtonOfSectionWithActiveOverlay()?.setAttribute('aria-expanded', 'false')
23
37
  }
24
38
 
25
39
  function cancelHideOverlayTask() {
@@ -30,7 +44,11 @@ function cancelHideOverlayTask() {
30
44
 
31
45
  function showOverlay() {
32
46
  cancelHideOverlayTask()
33
- document.getElementById(MENU_OVERLAY_ID)?.classList.add('visible')
47
+ const overlay = document.getElementById(MENU_OVERLAY_ID)
48
+ overlay?.removeAttribute('inert')
49
+ overlay?.removeAttribute('aria-hidden')
50
+ overlay?.classList.add('visible')
51
+ attachKeyboardListenersForOverlay?.()
34
52
  }
35
53
 
36
54
  function isMenuContentVisible() {
@@ -60,25 +78,21 @@ const Section = ({
60
78
  /* The overlay should appear if:
61
79
  * 1. The menu is compacted showing only the icons
62
80
  * 2. The section has some content to render OR:
63
- * 2.1 The section is active and there is a contextual menu for the active page.
64
- * 3. The section is inactive OR:
65
- * 2.1. The contextual menu is hidden.
81
+ * 3. The section is active and there is a contextual menu for the active page.
66
82
  */
67
- const layout = document.getElementById('layout')
68
- const isCompactedOnlyIcons = layout?.classList.contains('menu-compact-only-icons')
69
- return isCompactedOnlyIcons && (!!contentToRender || !!customContent || (hasContent && active)) && (!active || !isMenuContentVisible())
83
+ const { layout } = getLayoutElements()
84
+ const isCompactedOnlyIcons = layout?.classList.contains('menu-compact')
85
+ return isCompactedOnlyIcons && (!!contentToRender || !!customContent || (hasContent && active))
70
86
  }
71
87
 
72
- function showOverlayAndFixArrowPosition(event: React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.KeyboardEvent<any>) {
88
+ function prepareShowOverlay(event: React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.KeyboardEvent<any>) {
73
89
  if (!shouldShowOverlay()) return
74
90
  onOpen?.()
75
- const rect = (event.target as HTMLElement)?.getBoundingClientRect()
76
- const arrow: HTMLElement | null = document.querySelector(`#${MENU_OVERLAY_ID} .arrow`)
91
+ const anchorElement = event.target as HTMLElement
92
+ const accessibilityButton = anchorElement?.parentElement?.querySelector('button') as HTMLElement
93
+ accessibilityButton?.setAttribute('aria-expanded', 'true')
77
94
  setCurrentOverlay(id)
78
95
  showOverlay()
79
- if (rect && arrow) {
80
- arrow.style.top = `${rect.top + rect.height / 2 - ARROW_HEIGHT / 2}px`
81
- }
82
96
  }
83
97
 
84
98
  function click() {
@@ -95,7 +109,7 @@ const Section = ({
95
109
  href={href}
96
110
  target={target}
97
111
  onClick={click}
98
- onMouseEnter={showOverlayAndFixArrowPosition}
112
+ onMouseEnter={prepareShowOverlay}
99
113
  onMouseLeave={() => shouldShowOverlay() && hideOverlay()}
100
114
  title={labelText}
101
115
  aria-label={labelText}
@@ -104,7 +118,7 @@ const Section = ({
104
118
  {...(!href ? { 'tabIndex': 0 } : undefined)}
105
119
  >
106
120
  <Flex alignItems="center" justifyContent="center" px={5}>
107
- {icon}
121
+ <IconBox>{icon}</IconBox>
108
122
  {typeof label === 'string' ? <Text appearance="microtext1" className="section-label" ml={3}>{label}</Text> : label.element}
109
123
  </Flex>
110
124
  </a>
@@ -113,13 +127,12 @@ const Section = ({
113
127
  as="button"
114
128
  aria-label={interpolate(t.menuOptions, label)}
115
129
  aria-controls={MENU_OVERLAY_ID}
116
- aria-expanded={document.getElementById(MENU_OVERLAY_ID)?.classList.contains('visible')}
130
+ aria-expanded={false}
117
131
  onKeyDown={(event) => {
118
132
  if (event.key === 'Enter') {
119
- showOverlayAndFixArrowPosition(event)
133
+ prepareShowOverlay(event)
120
134
  }
121
- }
122
- }>
135
+ }}>
123
136
  <ChevronRight />
124
137
  </IconBox>
125
138
  }
@@ -130,7 +143,7 @@ const Section = ({
130
143
 
131
144
  const OverlayRenderer = ({ content, customContent }: Pick<MenuSection, 'content' | 'customContent'>) => {
132
145
  if (customContent) {
133
- return <> {customContent} </>
146
+ return <div id="custom-selectable-item"> {customContent} </div>
134
147
  }
135
148
 
136
149
  const data = typeof content === 'function' ? content() : content
@@ -141,15 +154,14 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
141
154
  const t = useTranslate(dictionary)
142
155
  // this is a mock state only used to force an update on the component.
143
156
  const [_, setUpdate] = useState(0)
144
- const onHide = () => hideOverlay()
145
157
 
146
158
  const toggleMenu = useCallback((hasContent: boolean) => {
147
159
  const layout = document.getElementById('layout')
148
160
  if (!layout) return
149
- if (layout.classList.contains('menu-compact-only-icons')) {
150
- layout.classList.remove('menu-compact-only-icons')
161
+ if (layout.classList.contains('menu-compact')) {
162
+ layout.classList.remove('menu-compact')
151
163
  } else {
152
- layout.classList.add('menu-compact-only-icons')
164
+ layout.classList.add('menu-compact')
153
165
  }
154
166
 
155
167
  if (hasContent) {
@@ -171,19 +183,19 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
171
183
  )
172
184
 
173
185
  function onPressEscape() {
174
- hideOverlay()
175
- const items = document.getElementsByClassName('section-submenu')
176
- if (!!items && !!currentOverlay && items.length > currentOverlay && items[currentOverlay].children.length > 1) {
177
- (items[currentOverlay].children[1] as HTMLElement).focus()
178
- }
186
+ getAccessibilityButtonOfSectionWithActiveOverlay()?.focus()
187
+ hideOverlayImmediately()
179
188
  }
180
189
 
181
- const wrapper = useKeyboardControls({
182
- onHide, visible: document.getElementById(MENU_OVERLAY_ID)?.classList.contains('visible') || false,
190
+ const { keyboardControlledElement: overlayRef, attachKeyboardListeners, detachKeyboardListeners } = useKeyboardControls({
191
+ onPressEscape,
183
192
  querySelectors: 'li a.action, #custom-selectable-item button, #custom-selectable-item input',
184
- onPressEscape: () => onPressEscape(),
185
193
  })
186
194
 
195
+ // fixme: this should definitely not be handled like this...
196
+ attachKeyboardListenersForOverlay = attachKeyboardListeners
197
+ detachKeyboardListenersForOverlay = detachKeyboardListeners
198
+
187
199
  /* This function renders the section preview in the overlay in normal circumstances. If the menu is hidden and the section is active,
188
200
  instead of rendering the section preview, it will render the actual menu content, which would be invisible otherwise.
189
201
  Below, the key is of extreme importance. It ensures React will consider every section content to be an entirely different
@@ -206,7 +218,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
206
218
 
207
219
  <Flex mb={7} alignItems="center">
208
220
  <button className="toggle sections-footer" onClick={() => toggleMenu(!!props.content || !!props.customContent)}
209
- title={t.toggle} tabIndex={-1} aria-hidden>
221
+ title={t.toggle} tabIndex={-1}>
210
222
  <IconBox>
211
223
  <Expand className="expand" />
212
224
  <Collapse className="collapse" />
@@ -217,7 +229,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
217
229
  <a href={props.settings?.href} onClick={props.settings?.onClick}
218
230
  className="sections-footer"
219
231
  {...(props.settings.active ? { 'aria-current': 'page' } : undefined)}>
220
- <Flex alignItems="center" >
232
+ <Flex alignItems="center" justifyContent="center">
221
233
  <IconBox aria-label={t.settingsIcon}>
222
234
  <Cog />
223
235
  </IconBox>
@@ -227,7 +239,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
227
239
  }
228
240
  </Flex>
229
241
 
230
- <div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={wrapper}>
242
+ <div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={overlayRef}>
231
243
  {renderMenuOverlay()}
232
244
  <div className="arrow"></div>
233
245
  </div>
@@ -81,7 +81,6 @@ export interface MenuSection extends Action {
81
81
 
82
82
  interface BaseMenuProps {
83
83
  sections?: MenuSection[],
84
- compact?: boolean,
85
84
  customContent?: ReactNode,
86
85
  settings?: {
87
86
  show?: boolean,
@@ -1,29 +1,34 @@
1
- import { useCallback, useEffect, useRef } from 'react'
1
+ import { useCallback, useRef } from 'react'
2
2
 
3
3
  interface Props {
4
- onHide?: () => void,
5
- visible: boolean,
4
+ /**
5
+ * A query selector that returns every html element that must be navigable through the keyboard.
6
+ */
6
7
  querySelectors: string,
8
+ /**
9
+ * Function to call when ESC is pressed. or when TAB is pressed at the last item in the list of items returned by the query selector.
10
+ */
7
11
  onPressEscape?: () => void,
12
+ /**
13
+ * Function to call when TAB is pressed at the last item in the list of items returned by the query selector. Will be the same as
14
+ * onPressEscape if not specified.
15
+ */
16
+ onPressLastTab?: () => void,
8
17
  }
9
18
 
10
- export function useKeyboardControls({ onHide, visible, querySelectors, onPressEscape }: Props) {
11
- const wrapper = useRef<HTMLDivElement>(null)
12
-
13
- const onRemoveListeners = () =>{
14
- document.removeEventListener('keydown', keyboardControls)
15
- document.removeEventListener('click', hide)
16
- }
19
+ export function useKeyboardControls({ querySelectors, onPressEscape, onPressLastTab = onPressEscape }: Props) {
20
+ const keyboardControlledElement = useRef<HTMLDivElement>(null)
21
+ const listeners = useRef<Pick<Props, 'onPressEscape' | 'onPressLastTab'>>({})
22
+ listeners.current = { onPressEscape, onPressLastTab }
17
23
 
18
24
  const keyboardControls = useCallback((event: KeyboardEvent) => {
19
25
  const target = event?.target as HTMLElement | null
20
26
 
21
27
  function getSelectableAnchors() {
22
- return wrapper.current?.querySelectorAll(querySelectors) ?? []
28
+ return keyboardControlledElement.current?.querySelectorAll(querySelectors) ?? []
23
29
  }
24
30
 
25
31
  function handleArrows(key = event.key) {
26
-
27
32
  const anchors = getSelectableAnchors()
28
33
  let i = 0
29
34
  while (i < anchors.length && document.activeElement !== anchors[i]) i++
@@ -33,56 +38,33 @@ export function useKeyboardControls({ onHide, visible, querySelectors, onPressEs
33
38
 
34
39
  const handlers: Record<string, (() => void) | undefined> = {
35
40
  Escape: () => {
36
- onPressEscape?.()
37
- onHide?.()
38
- onRemoveListeners()
41
+ listeners.current.onPressEscape?.()
42
+ event.stopPropagation()
43
+ event.preventDefault()
39
44
  },
40
45
  Enter: () => {
41
46
  target?.click()
42
47
  },
43
48
  Tab: () => {
44
49
  const anchors = getSelectableAnchors()
45
- if (document.activeElement === anchors[anchors.length - 1]) onHide?.()
46
- else {
47
- handleArrows('ArrowDown')
48
- event.preventDefault()
49
- }
50
- },
51
- ArrowUp: () => {
52
- handleArrows()
53
- },
54
- ArrowDown: () => {
55
- handleArrows()
50
+ if (document.activeElement === anchors[anchors.length - 1]) listeners.current.onPressLastTab?.()
51
+ else handleArrows('ArrowDown')
52
+ event.preventDefault()
56
53
  },
54
+ ArrowUp: handleArrows,
55
+ ArrowDown: handleArrows,
57
56
  }
58
57
 
59
58
  handlers[event.key]?.()
60
- }, [onPressEscape, visible])
59
+ }, [])
61
60
 
62
- const hide = useCallback((event: Event) => {
63
- const target = (event.target as HTMLElement | null)
64
- // if the element is not in the DOM anymore, we'll consider the click was inside the selection list
65
- const isClickInsideSelectionList = !target?.isConnected || wrapper.current?.contains(target)
66
- const isAction = target?.classList?.contains('action') || !!target?.closest('.action')
67
- if (!isClickInsideSelectionList || isAction) onHide?.()
61
+ const attachKeyboardListeners = useCallback(() => {
62
+ document.addEventListener('keydown', keyboardControls)
68
63
  }, [])
69
64
 
70
- useEffect(() => {
71
- if (visible) {
72
- document.addEventListener('keydown', keyboardControls)
73
- document.addEventListener('keydown', keyboardControls)
74
- if (onHide) setTimeout(() => document.addEventListener('click', hide), 50)
75
- }
76
- else {
77
- onRemoveListeners()
78
- }
79
-
80
- return () => {
81
- // Remove the event listener
82
- document.removeEventListener('keydown', keyboardControls)
83
- document.removeEventListener('click', hide)
84
- }
85
- }, [visible, keyboardControls])
65
+ const detachKeyboardListeners = useCallback(() => {
66
+ document.removeEventListener('keydown', keyboardControls)
67
+ }, [])
86
68
 
87
- return wrapper
69
+ return { keyboardControlledElement, attachKeyboardListeners, detachKeyboardListeners }
88
70
  }
package/src/layout.css CHANGED
@@ -45,16 +45,16 @@ body {
45
45
  --modal-animation-duration: 0.3s;
46
46
  --right-panel-animation-duration: 0.3s;
47
47
  --menu-animation-duration: 0.3s;
48
- --menu-overlay-width: 332px;
48
+ --menu-overlay-width: 240px;
49
49
  --toastify-font-family: 'Roboto', sans-serif;
50
50
  }
51
51
 
52
- #layout.menu-compact:not(.menu-compact-only-icons) {
52
+ #layout:not(.menu-compact) {
53
53
  --menu-sections-width: 135px;
54
54
  --menu-item-height: 56px;
55
55
  }
56
56
 
57
- #layout.menu-compact-only-icons {
57
+ #layout.menu-compact {
58
58
  --menu-sections-width: 56px;
59
59
  --menu-item-height: 56px;
60
60
  }
@@ -87,7 +87,6 @@ body {
87
87
  display: flex;
88
88
  flex-direction: column;
89
89
  background-color: var(--light-300);
90
- border-top-left-radius: 0.5rem;
91
90
  align-items: center;
92
91
  padding: 24px;
93
92
  transition: left ease-in-out var(--menu-animation-duration);
@@ -133,20 +132,24 @@ body {
133
132
  }
134
133
 
135
134
  #menu .toggle .expand,
136
- #layout.menu-compact-only-icons .toggle .collapse {
135
+ #layout.menu-compact .toggle .collapse {
137
136
  opacity: 0;
138
137
  }
139
138
 
140
139
  #menu .toggle .collapse,
141
- #layout.menu-compact-only-icons .toggle .expand {
140
+ #layout.menu-compact .toggle .expand {
142
141
  opacity: 1;
143
142
  }
144
143
 
145
- #layout.menu-compact-only-icons .section-label {
144
+ #layout .section-label {
145
+ line-height: 0.875rem;
146
+ }
147
+
148
+ #layout.menu-compact .section-label {
146
149
  display: none;
147
150
  }
148
151
 
149
- #layout:not(.menu-compact-only-icons) .section-label {
152
+ #layout:not(.menu-compact) .section-label {
150
153
  display: block;
151
154
  }
152
155
 
@@ -154,10 +157,12 @@ body {
154
157
  width: var(--menu-sections-width);
155
158
  display: flex;
156
159
  flex-direction: column;
157
- padding: 10px 0;
160
+ padding: 0 0 10px;
158
161
  justify-content: space-between;
159
162
  background-color: var(--light-400);
160
163
  position: relative;
164
+ border-right: 1px solid var(--light-300);
165
+ border-top: 1px solid var(--light-300);
161
166
  }
162
167
 
163
168
  #menuSections .sections-footer {
@@ -179,6 +184,7 @@ body {
179
184
  transition: background-color 0.2s;
180
185
  cursor: pointer;
181
186
  position: relative;
187
+ z-index: 2;
182
188
  }
183
189
 
184
190
  #menuSections > ul li a:before {
@@ -194,6 +200,7 @@ body {
194
200
 
195
201
  #menuSections > ul li.active a {
196
202
  background-color: var(--light-500);
203
+ border-right: 1px solid var(--light-300);
197
204
  }
198
205
 
199
206
  #menuSections > ul li.active a:before {
@@ -206,6 +213,7 @@ body {
206
213
  #menuSections .toggle:focus,
207
214
  #menuSections > ul li a:focus {
208
215
  background: var(--light-500);
216
+ border-right: 1px solid var(--light-300);
209
217
  }
210
218
 
211
219
  #menuSections > ul li:not(.active) a:hover:before {
@@ -220,11 +228,12 @@ body {
220
228
  #menuContentOverlay {
221
229
  width: var(--menu-overlay-width);
222
230
  position: fixed;
223
- top: calc(var(--header-height) + 15px);
224
- left: calc(var(--menu-sections-width) + 15px);
225
- bottom: 15px;
231
+ top: calc(var(--header-height));
232
+ left: calc(var(--menu-sections-width));
233
+ bottom: 1px;
226
234
  background-color: var(--light-500);
227
- border-radius: 0 8px 8px 0;
235
+ border-radius: 0px 8px 8px 0px;
236
+ border-top: 1px solid var(--light-300);
228
237
  display: flex;
229
238
  flex-direction: column;
230
239
  overflow: hidden;
@@ -244,19 +253,6 @@ body {
244
253
  overflow: auto;
245
254
  }
246
255
 
247
- #menuContentOverlay > .arrow {
248
- width: 0;
249
- height: 0;
250
- border-top: 12px solid transparent;
251
- border-bottom: 12px solid transparent;
252
- border-right: 12px solid var(--light-400);
253
- position: fixed;
254
- /* header + menu sections padding + item height / 2 - arrow height / 2 */
255
- top: calc(var(--header-height) + 10px + var(--menu-item-height) / 2 - 12px);
256
- left: calc(var(--menu-sections-width) + 3px);
257
- transition: top ease-out 0.3s;
258
- }
259
-
260
256
  #menuContent {
261
257
  width: var(--menu-content-width);
262
258
  transition: left ease-out var(--menu-animation-duration);
@@ -266,7 +262,7 @@ body {
266
262
  top: 0;
267
263
  bottom: 0;
268
264
  left: calc(var(--menu-sections-width) - var(--menu-content-width) - 2px); /* 2px from border */
269
- border-left: 2px solid var(--light-500);
265
+ border-top: 1px solid var(--light-300);
270
266
  }
271
267
 
272
268
  #layout.menu-content-visible #menuContent {
@@ -458,6 +454,7 @@ i {
458
454
  top: 27%;
459
455
  right: 10px;
460
456
  background-color: inherit;
457
+ z-index: 1;
461
458
  }
462
459
 
463
460
  #menuSections .section-submenu-icon:focus-visible {
@@ -1,12 +0,0 @@
1
- export interface ErrorDescription {
2
- code?: number;
3
- message?: string;
4
- debug?: boolean;
5
- }
6
- export type DescriptionFn = (error: any) => ErrorDescription;
7
- export declare class ErrorDescriptor {
8
- private static descriptionFunction;
9
- static setDescriptionFunction(fn: DescriptionFn): void;
10
- static describe(error: any): ErrorDescription;
11
- }
12
- //# sourceMappingURL=ErrorDescriptor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErrorDescriptor.d.ts","sourceRoot":"","sources":["../../../src/components/error/ErrorDescriptor.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,gBAAgB,CAAA;AAE5D,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAEhC;IAEF,MAAM,CAAC,sBAAsB,CAAC,EAAE,EAAE,aAAa;IAI/C,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG;CAG3B"}
@@ -1,17 +0,0 @@
1
- export class ErrorDescriptor {
2
- static setDescriptionFunction(fn) {
3
- this.descriptionFunction = fn;
4
- }
5
- static describe(error) {
6
- return this.descriptionFunction(error);
7
- }
8
- }
9
- Object.defineProperty(ErrorDescriptor, "descriptionFunction", {
10
- enumerable: true,
11
- configurable: true,
12
- writable: true,
13
- value: error => ({
14
- message: error.message || `${error}`,
15
- })
16
- });
17
- //# sourceMappingURL=ErrorDescriptor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErrorDescriptor.js","sourceRoot":"","sources":["../../../src/components/error/ErrorDescriptor.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,eAAe;IAK1B,MAAM,CAAC,sBAAsB,CAAC,EAAiB;QAC7C,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAA;IAC/B,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,KAAU;QACxB,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC;;AAVc;;;;WAAqC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5D,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,GAAG,KAAK,EAAE;KACrC,CAAC;GAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="react" />
2
- export declare function useCheckTextOverflow(): {
3
- overflow: boolean;
4
- ref: import("react").RefObject<HTMLParagraphElement>;
5
- };
6
- //# sourceMappingURL=useCheckTextOverflow.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCheckTextOverflow.d.ts","sourceRoot":"","sources":["../../../src/components/menu/useCheckTextOverflow.tsx"],"names":[],"mappings":";AAEA,wBAAgB,oBAAoB;;;EAuBnC"}
@@ -1,20 +0,0 @@
1
- import { useState, useRef, useEffect } from 'react';
2
- export function useCheckTextOverflow() {
3
- const [overflow, setOverflow] = useState(false);
4
- const ref = useRef(null);
5
- const checkOverflow = () => {
6
- if (!ref.current) {
7
- return;
8
- }
9
- const hasOverflow = ref.current.offsetWidth < ref.current.scrollWidth;
10
- if (hasOverflow === overflow) {
11
- return;
12
- }
13
- setOverflow(hasOverflow);
14
- };
15
- useEffect(() => {
16
- checkOverflow();
17
- }, [ref.current]);
18
- return { overflow, ref };
19
- }
20
- //# sourceMappingURL=useCheckTextOverflow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCheckTextOverflow.js","sourceRoot":"","sources":["../../../src/components/menu/useCheckTextOverflow.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpD,MAAM,UAAU,oBAAoB;IAClC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAA;IACxD,MAAM,GAAG,GAAG,MAAM,CAAuB,IAAI,CAAC,CAAA;IAE9C,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAA;QAErE,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAM;QACR,CAAC;QAED,WAAW,CAAC,WAAW,CAAC,CAAA;IAC1B,CAAC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,EAAE,CAAA;IACjB,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IAEjB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAA;AAC1B,CAAC"}