@stack-spot/portal-layout 0.0.33 → 0.0.34

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 +6 -4
  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 +42 -26
  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 +14 -8
  24. package/dist/utils.js.map +1 -1
  25. package/package.json +5 -5
  26. package/src/Layout.tsx +6 -5
  27. package/src/components/SelectionList.tsx +24 -2
  28. package/src/components/menu/MenuSections.tsx +47 -29
  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 +14 -8
  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
@@ -2,6 +2,8 @@ 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'
@@ -12,14 +14,27 @@ const MENU_OVERLAY_ID = 'menuContentOverlay'
12
14
 
13
15
  let hideOverlayTask: number | undefined
14
16
 
17
+ // fixme: this should definitely not be handled like this...
18
+ let attachKeyboardListenersForOverlay: () => void
19
+ let detachKeyboardListenersForOverlay: () => void
20
+
15
21
  function hideOverlay() {
16
22
  if (hideOverlayTask !== undefined) return
17
23
  hideOverlayTask = window.setTimeout(hideOverlayImmediately, HIDE_OVERLAY_DELAY_MS)
18
24
  }
19
25
 
26
+ function getAccessibilityButtonOfSectionWithActiveOverlay(): HTMLElement | null | undefined {
27
+ return document.getElementById(elementIds.menuSections)?.querySelector('button[aria-expanded="true"]')
28
+ }
29
+
20
30
  // eslint-disable-next-line react-refresh/only-export-components
21
31
  export function hideOverlayImmediately() {
22
- document.getElementById(MENU_OVERLAY_ID)?.classList.remove('visible')
32
+ detachKeyboardListenersForOverlay?.()
33
+ const overlay = document.getElementById(MENU_OVERLAY_ID)
34
+ overlay?.setAttribute('inert', '')
35
+ overlay?.setAttribute('aria-hidden', '')
36
+ overlay?.classList.remove('visible')
37
+ getAccessibilityButtonOfSectionWithActiveOverlay()?.setAttribute('aria-expanded', 'false')
23
38
  }
24
39
 
25
40
  function cancelHideOverlayTask() {
@@ -30,7 +45,11 @@ function cancelHideOverlayTask() {
30
45
 
31
46
  function showOverlay() {
32
47
  cancelHideOverlayTask()
33
- document.getElementById(MENU_OVERLAY_ID)?.classList.add('visible')
48
+ const overlay = document.getElementById(MENU_OVERLAY_ID)
49
+ overlay?.removeAttribute('inert')
50
+ overlay?.removeAttribute('aria-hidden')
51
+ overlay?.classList.add('visible')
52
+ attachKeyboardListenersForOverlay?.()
34
53
  }
35
54
 
36
55
  function isMenuContentVisible() {
@@ -60,19 +79,20 @@ const Section = ({
60
79
  /* The overlay should appear if:
61
80
  * 1. The menu is compacted showing only the icons
62
81
  * 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.
82
+ * 3. The section is active and there is a contextual menu for the active page.
66
83
  */
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())
84
+ const { layout } = getLayoutElements()
85
+ const isCompactedOnlyIcons = layout?.classList.contains('menu-compact')
86
+ return isCompactedOnlyIcons && (!!contentToRender || !!customContent || (hasContent && active))
70
87
  }
71
88
 
72
89
  function showOverlayAndFixArrowPosition(event: React.MouseEvent<HTMLAnchorElement, MouseEvent> | React.KeyboardEvent<any>) {
73
90
  if (!shouldShowOverlay()) return
74
91
  onOpen?.()
75
- const rect = (event.target as HTMLElement)?.getBoundingClientRect()
92
+ const anchorElement = event.target as HTMLElement
93
+ const accessibilityButton = anchorElement?.parentElement?.querySelector('button') as HTMLElement
94
+ accessibilityButton?.setAttribute('aria-expanded', 'true')
95
+ const rect = anchorElement?.getBoundingClientRect()
76
96
  const arrow: HTMLElement | null = document.querySelector(`#${MENU_OVERLAY_ID} .arrow`)
77
97
  setCurrentOverlay(id)
78
98
  showOverlay()
@@ -104,7 +124,7 @@ const Section = ({
104
124
  {...(!href ? { 'tabIndex': 0 } : undefined)}
105
125
  >
106
126
  <Flex alignItems="center" justifyContent="center" px={5}>
107
- {icon}
127
+ <IconBox>{icon}</IconBox>
108
128
  {typeof label === 'string' ? <Text appearance="microtext1" className="section-label" ml={3}>{label}</Text> : label.element}
109
129
  </Flex>
110
130
  </a>
@@ -113,13 +133,12 @@ const Section = ({
113
133
  as="button"
114
134
  aria-label={interpolate(t.menuOptions, label)}
115
135
  aria-controls={MENU_OVERLAY_ID}
116
- aria-expanded={document.getElementById(MENU_OVERLAY_ID)?.classList.contains('visible')}
136
+ aria-expanded={false}
117
137
  onKeyDown={(event) => {
118
138
  if (event.key === 'Enter') {
119
139
  showOverlayAndFixArrowPosition(event)
120
140
  }
121
- }
122
- }>
141
+ }}>
123
142
  <ChevronRight />
124
143
  </IconBox>
125
144
  }
@@ -130,7 +149,7 @@ const Section = ({
130
149
 
131
150
  const OverlayRenderer = ({ content, customContent }: Pick<MenuSection, 'content' | 'customContent'>) => {
132
151
  if (customContent) {
133
- return <> {customContent} </>
152
+ return <div id="custom-selectable-item"> {customContent} </div>
134
153
  }
135
154
 
136
155
  const data = typeof content === 'function' ? content() : content
@@ -141,15 +160,14 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
141
160
  const t = useTranslate(dictionary)
142
161
  // this is a mock state only used to force an update on the component.
143
162
  const [_, setUpdate] = useState(0)
144
- const onHide = () => hideOverlay()
145
163
 
146
164
  const toggleMenu = useCallback((hasContent: boolean) => {
147
165
  const layout = document.getElementById('layout')
148
166
  if (!layout) return
149
- if (layout.classList.contains('menu-compact-only-icons')) {
150
- layout.classList.remove('menu-compact-only-icons')
167
+ if (layout.classList.contains('menu-compact')) {
168
+ layout.classList.remove('menu-compact')
151
169
  } else {
152
- layout.classList.add('menu-compact-only-icons')
170
+ layout.classList.add('menu-compact')
153
171
  }
154
172
 
155
173
  if (hasContent) {
@@ -171,19 +189,19 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
171
189
  )
172
190
 
173
191
  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
- }
192
+ getAccessibilityButtonOfSectionWithActiveOverlay()?.focus()
193
+ hideOverlayImmediately()
179
194
  }
180
195
 
181
- const wrapper = useKeyboardControls({
182
- onHide, visible: document.getElementById(MENU_OVERLAY_ID)?.classList.contains('visible') || false,
196
+ const { keyboardControlledElement: overlayRef, attachKeyboardListeners, detachKeyboardListeners } = useKeyboardControls({
197
+ onPressEscape,
183
198
  querySelectors: 'li a.action, #custom-selectable-item button, #custom-selectable-item input',
184
- onPressEscape: () => onPressEscape(),
185
199
  })
186
200
 
201
+ // fixme: this should definitely not be handled like this...
202
+ attachKeyboardListenersForOverlay = attachKeyboardListeners
203
+ detachKeyboardListenersForOverlay = detachKeyboardListeners
204
+
187
205
  /* This function renders the section preview in the overlay in normal circumstances. If the menu is hidden and the section is active,
188
206
  instead of rendering the section preview, it will render the actual menu content, which would be invisible otherwise.
189
207
  Below, the key is of extreme importance. It ensures React will consider every section content to be an entirely different
@@ -206,7 +224,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
206
224
 
207
225
  <Flex mb={7} alignItems="center">
208
226
  <button className="toggle sections-footer" onClick={() => toggleMenu(!!props.content || !!props.customContent)}
209
- title={t.toggle} tabIndex={-1} aria-hidden>
227
+ title={t.toggle} tabIndex={-1}>
210
228
  <IconBox>
211
229
  <Expand className="expand" />
212
230
  <Collapse className="collapse" />
@@ -217,7 +235,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
217
235
  <a href={props.settings?.href} onClick={props.settings?.onClick}
218
236
  className="sections-footer"
219
237
  {...(props.settings.active ? { 'aria-current': 'page' } : undefined)}>
220
- <Flex alignItems="center" >
238
+ <Flex alignItems="center" justifyContent="center">
221
239
  <IconBox aria-label={t.settingsIcon}>
222
240
  <Cog />
223
241
  </IconBox>
@@ -227,7 +245,7 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
227
245
  }
228
246
  </Flex>
229
247
 
230
- <div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={wrapper}>
248
+ <div id={MENU_OVERLAY_ID} onMouseEnter={showOverlay} onMouseLeave={hideOverlay} ref={overlayRef}>
231
249
  {renderMenuOverlay()}
232
250
  <div className="arrow"></div>
233
251
  </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
@@ -49,12 +49,12 @@ body {
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
  }
@@ -133,20 +133,24 @@ body {
133
133
  }
134
134
 
135
135
  #menu .toggle .expand,
136
- #layout.menu-compact-only-icons .toggle .collapse {
136
+ #layout.menu-compact .toggle .collapse {
137
137
  opacity: 0;
138
138
  }
139
139
 
140
140
  #menu .toggle .collapse,
141
- #layout.menu-compact-only-icons .toggle .expand {
141
+ #layout.menu-compact .toggle .expand {
142
142
  opacity: 1;
143
143
  }
144
144
 
145
- #layout.menu-compact-only-icons .section-label {
145
+ #layout .section-label {
146
+ line-height: 0.875rem;
147
+ }
148
+
149
+ #layout.menu-compact .section-label {
146
150
  display: none;
147
151
  }
148
152
 
149
- #layout:not(.menu-compact-only-icons) .section-label {
153
+ #layout:not(.menu-compact) .section-label {
150
154
  display: block;
151
155
  }
152
156
 
@@ -179,6 +183,7 @@ body {
179
183
  transition: background-color 0.2s;
180
184
  cursor: pointer;
181
185
  position: relative;
186
+ z-index: 2;
182
187
  }
183
188
 
184
189
  #menuSections > ul li a:before {
@@ -224,7 +229,7 @@ body {
224
229
  left: calc(var(--menu-sections-width) + 15px);
225
230
  bottom: 15px;
226
231
  background-color: var(--light-500);
227
- border-radius: 0 8px 8px 0;
232
+ border-radius: 8px;
228
233
  display: flex;
229
234
  flex-direction: column;
230
235
  overflow: hidden;
@@ -249,7 +254,7 @@ body {
249
254
  height: 0;
250
255
  border-top: 12px solid transparent;
251
256
  border-bottom: 12px solid transparent;
252
- border-right: 12px solid var(--light-400);
257
+ border-right: 12px solid var(--light-500);
253
258
  position: fixed;
254
259
  /* header + menu sections padding + item height / 2 - arrow height / 2 */
255
260
  top: calc(var(--header-height) + 10px + var(--menu-item-height) / 2 - 12px);
@@ -458,6 +463,7 @@ i {
458
463
  top: 27%;
459
464
  right: 10px;
460
465
  background-color: inherit;
466
+ z-index: 1;
461
467
  }
462
468
 
463
469
  #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"}