-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[uptime] Adjust the theme colors for uptime monitors browser screensh…
…ot labels. (#115543) * Add useBreakpoints reactive hook for uptime. Adjusted color/contrast and alignment for timestamp screenshot popup footer. #96122
- Loading branch information
Showing
5 changed files
with
252 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
x-pack/plugins/uptime/public/hooks/use_breakpoints.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { BREAKPOINTS } from '@elastic/eui'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
import { useBreakpoints } from './use_breakpoints'; | ||
|
||
describe('use_breakpoints', () => { | ||
describe('useBreakpoints', () => { | ||
const width = global.innerWidth; | ||
|
||
beforeEach(() => { | ||
jest.useFakeTimers(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.runOnlyPendingTimers(); | ||
jest.useRealTimers(); | ||
}); | ||
|
||
afterAll(() => { | ||
(global as { innerWidth: number }).innerWidth = width; | ||
}); | ||
|
||
it('should only return up => false and down => true for "xs" when width is less than BREAKPOINTS.xs', () => { | ||
(global as { innerWidth: number }).innerWidth = BREAKPOINTS.xs - 1; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.up('xs')).toBeFalsy(); | ||
expect(result.current.down('xs')).toBeTruthy(); | ||
}); | ||
|
||
it('should only return up => true and down => false for "xs" when width is above or equal BREAKPOINTS.xs', () => { | ||
(global as { innerWidth: number }).innerWidth = BREAKPOINTS.xs; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.up('xs')).toBeTruthy(); | ||
expect(result.current.down('xs')).toBeFalsy(); | ||
}); | ||
|
||
it('should return down => true for "m" when width equals BREAKPOINTS.l', () => { | ||
(global as { innerWidth: number }).innerWidth = BREAKPOINTS.l; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.up('m')).toBeTruthy(); | ||
expect(result.current.down('m')).toBeFalsy(); | ||
}); | ||
|
||
it('should return `between` => true for "m" and "xl" when width equals BREAKPOINTS.l', () => { | ||
(global as { innerWidth: number }).innerWidth = BREAKPOINTS.l; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.between('m', 'xl')).toBeTruthy(); | ||
}); | ||
|
||
it('should return `between` => true for "s" and "m" when width equals BREAKPOINTS.s', () => { | ||
(global as { innerWidth: number }).innerWidth = BREAKPOINTS.s; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.between('s', 'm')).toBeTruthy(); | ||
}); | ||
|
||
it('should return up => true for all when size is > xxxl+', () => { | ||
(global as { innerWidth: number }).innerWidth = 3000; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
expect(result.current.up('xs')).toBeTruthy(); | ||
expect(result.current.up('s')).toBeTruthy(); | ||
expect(result.current.up('m')).toBeTruthy(); | ||
expect(result.current.up('l')).toBeTruthy(); | ||
expect(result.current.up('xl')).toBeTruthy(); | ||
expect(result.current.up('xxl')).toBeTruthy(); | ||
expect(result.current.up('xxxl')).toBeTruthy(); | ||
}); | ||
|
||
it('should determine `isIpad (Portrait)', () => { | ||
(global as { innerWidth: number }).innerWidth = 768; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
const isIpad = result.current.up('m') && result.current.down('l'); | ||
expect(isIpad).toEqual(true); | ||
}); | ||
|
||
it('should determine `isMobile (Portrait)`', () => { | ||
(global as { innerWidth: number }).innerWidth = 480; | ||
const { result } = renderHook(() => useBreakpoints()); | ||
|
||
const isMobile = result.current.up('xs') && result.current.down('s'); | ||
expect(isMobile).toEqual(true); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { useCallback, useState } from 'react'; | ||
import useWindowSize from 'react-use/lib/useWindowSize'; | ||
import useDebounce from 'react-use/lib/useDebounce'; | ||
|
||
import { BREAKPOINTS, EuiBreakpointSize } from '@elastic/eui'; | ||
|
||
// Custom breakpoints | ||
const BREAKPOINT_XL = 1599; // Overriding the theme's default 'xl' breakpoint | ||
const BREAKPOINT_XXL = 1599; | ||
const BREAKPOINT_XXXL = 2000; | ||
|
||
export type BreakpointKey = EuiBreakpointSize | 'xxl' | 'xxxl'; | ||
|
||
type BreakpointPredicate = (breakpointKey: BreakpointKey) => boolean; | ||
type BreakpointRangePredicate = (from: BreakpointKey, to: BreakpointKey) => boolean; | ||
|
||
/** | ||
* Returns the predicates functions used to determine whether the current device's width is above or below the asked | ||
* breakpoint. (Implementation inspired by React Material UI). | ||
* | ||
* @example | ||
* const { breakpoints } = useBreakpoints(); | ||
* const isMobile = breakpoint.down('m'); | ||
* | ||
* @example | ||
* const { breakpoints } = useBreakpoints(); | ||
* const isTablet = breakpoint.between('m', 'l'); | ||
* | ||
* @param debounce {number} Debounce interval for optimization | ||
* | ||
* @returns { {up: BreakpointPredicate, down: BreakpointPredicate, between: BreakpointRangePredicate} } | ||
* Returns object containing predicates which determine whether the current device's width lies above, below or | ||
* in-between the given breakpoint(s) | ||
* { | ||
* up => Returns `true` if the current width is equal or above (inclusive) the given breakpoint size, | ||
* or `false` otherwise. | ||
* down => Returns `true` if the current width is below (exclusive) the given breakpoint size, or `false` otherwise. | ||
* between => Returns `true` if the current width is equal or above (inclusive) the corresponding size of | ||
* `fromBreakpointKey` AND is below (exclusive) the corresponding width of `toBreakpointKey`. | ||
* Returns `false` otherwise. | ||
* } | ||
*/ | ||
export function useBreakpoints(debounce = 50) { | ||
const { width } = useWindowSize(); | ||
const [debouncedWidth, setDebouncedWidth] = useState(width); | ||
|
||
const up = useCallback<BreakpointPredicate>( | ||
(breakpointKey: BreakpointKey) => isUp(debouncedWidth, breakpointKey), | ||
[debouncedWidth] | ||
); | ||
const down = useCallback<BreakpointPredicate>( | ||
(breakpointKey: BreakpointKey) => isDown(debouncedWidth, breakpointKey), | ||
[debouncedWidth] | ||
); | ||
|
||
const between = useCallback<BreakpointRangePredicate>( | ||
(fromBreakpointKey: BreakpointKey, toBreakpointKey: BreakpointKey) => | ||
isBetween(debouncedWidth, fromBreakpointKey, toBreakpointKey), | ||
[debouncedWidth] | ||
); | ||
|
||
useDebounce( | ||
() => { | ||
setDebouncedWidth(width); | ||
}, | ||
debounce, | ||
[width] | ||
); | ||
|
||
return { up, down, between, debouncedWidth }; | ||
} | ||
|
||
/** | ||
* Returns the corresponding device width against the provided breakpoint key, either the overridden value or the | ||
* default value from theme. | ||
* @param key {BreakpointKey} string key representing the device breakpoint e.g. 'xs', 's', 'xxxl' | ||
*/ | ||
function getSizeForBreakpointKey(key: BreakpointKey): number { | ||
switch (key) { | ||
case 'xxxl': | ||
return BREAKPOINT_XXXL; | ||
case 'xxl': | ||
return BREAKPOINT_XXL; | ||
case 'xl': | ||
return BREAKPOINT_XL; | ||
case 'l': | ||
return BREAKPOINTS.l; | ||
case 'm': | ||
return BREAKPOINTS.m; | ||
case 's': | ||
return BREAKPOINTS.s; | ||
} | ||
|
||
return BREAKPOINTS.xs; | ||
} | ||
|
||
function isUp(size: number, breakpointKey: BreakpointKey) { | ||
return size >= getSizeForBreakpointKey(breakpointKey); | ||
} | ||
|
||
function isDown(size: number, breakpointKey: BreakpointKey) { | ||
return size < getSizeForBreakpointKey(breakpointKey); | ||
} | ||
|
||
function isBetween(size: number, fromBreakpointKey: BreakpointKey, toBreakpointKey: BreakpointKey) { | ||
return isUp(size, fromBreakpointKey) && isDown(size, toBreakpointKey); | ||
} |