Skip to content

Commit

Permalink
fix(Dropdown): enhance height calcilation and add support for strict …
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker authored Dec 9, 2024
1 parent 752180a commit 32b7b5b
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 85 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,8 @@ html[data-visual-test] .dnb-modal__overlay, .dnb-modal__overlay--no-animation {
max-height: 100vh;
overflow: hidden;
}
.dnb-dialog .dnb-scroll-view {
.dnb-dialog > .dnb-scroll-view {
height: 100%;
max-height: 90vh;
}
.dnb-dialog__inner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
max-height: 100vh;
overflow: hidden;

.dnb-scroll-view {
& > .dnb-scroll-view {
height: 100%; // ensure a Dropdown opens with the full height
max-height: 90vh; // make it scrollable
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,70 +160,70 @@ describe.each(['ui', 'sbanken'])('Dropdown for %s', (themeName) => {
url: '/uilib/components/dropdown/demos',
pageViewport: {
width: 480,
height: 480,
height: 480 * 2,
},
})

it('have to match different item directions', async () => {
it('have to match the tertiary variant opened on left side', async () => {
const screenshot = await makeScreenshot({
style: {
'padding-top': '16rem',
},
selector: '[data-visual-test="dropdown-item-directions"]',
selector: '[data-visual-test="dropdown-tertiary"]',
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-item-directions"] .dnb-dropdown__trigger',
'[data-visual-test="dropdown-tertiary"] .dnb-dropdown__trigger',
simulateAfter: { keypress: 'Escape' },
style: {
'padding-bottom': '16rem',
},
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the dropdown as more_menu opened on left side', async () => {
it('have to match the tertiary variant opened on right side', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="dropdown-more_menu"]',
selector: '[data-visual-test="dropdown-tertiary-right"]',
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-more_menu"] .dnb-dropdown:first-child button',
'[data-visual-test="dropdown-tertiary-right"] .dnb-dropdown__trigger',
simulateAfter: { keypress: 'Escape' },
style: {
'padding-bottom': '16rem',
},
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the dropdown as more_menu opened on right side', async () => {
it('have to match different item directions', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="dropdown-more_menu"]',
style: {
'padding-top': '16rem',
},
selector: '[data-visual-test="dropdown-item-directions"]',
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-more_menu"] .dnb-dropdown:nth-child(2) button',
'[data-visual-test="dropdown-item-directions"] .dnb-dropdown__trigger',
simulateAfter: { keypress: 'Escape' },
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the tertiary variant opened on left side', async () => {
it('have to match the dropdown as more_menu opened on left side', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="dropdown-tertiary"]',
selector: '[data-visual-test="dropdown-more_menu"]',
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-tertiary"] .dnb-dropdown__trigger',
'[data-visual-test="dropdown-more_menu"] .dnb-dropdown:first-child button',
simulateAfter: { keypress: 'Escape' },
style: {
'padding-bottom': '16rem',
},
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the tertiary variant opened on right side', async () => {
it('have to match the dropdown as more_menu opened on right side', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="dropdown-tertiary-right"]',
selector: '[data-visual-test="dropdown-more_menu"]',
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-tertiary-right"] .dnb-dropdown__trigger',
'[data-visual-test="dropdown-more_menu"] .dnb-dropdown:nth-child(2) button',
simulateAfter: { keypress: 'Escape' },
style: {
'padding-bottom': '16rem',
},
})
expect(screenshot).toMatchImageSnapshot()
})
Expand All @@ -234,6 +234,7 @@ describe.each(['ui', 'sbanken'])('Dropdown for %s', (themeName) => {
simulate: 'click',
simulateSelector:
'[data-visual-test="dropdown-action_menu-custom"] .dnb-dropdown__trigger',
simulateAfter: { keypress: 'Escape' },
style: {
width: '14rem',
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import {
Drawer,
GlobalStatus,
} from '../..'
import { Flex, Link } from '../../..'
import { Dialog, Flex, Link } from '../../..'
import { DrawerListDataArray } from '../../../fragments/DrawerList'
import { Provider } from '../../../shared'
import { Field, Form } from '../../../extensions/forms'

export default {
title: 'Eufemia/Components/Dropdown',
Expand Down Expand Up @@ -1004,3 +1005,42 @@ export const GlobalStatusExample = () => {
</>
)
}

export function InDialog() {
const list = Array(30).fill('Content')
return (
<Dialog
alignContent="left"
maxWidth="35rem"
title="Ny melding"
openState
noAnimation
>
<Form.Handler>
<Flex.Stack>
<Field.Selection
data={list}
label="Hva gjelder henvendelsen?"
dropdownProps={{
title: 'Velg fra liste',
direction: 'bottom',
}}
/>

<Field.Selection
data={list}
label="Emne"
dropdownProps={{
title: 'Velg fra liste',
direction: 'bottom',
}}
/>

<Dialog.Action innerSpace={{ top: 'small' }}>
<Form.SubmitButton />
</Dialog.Action>
</Flex.Stack>
</Form.Handler>
</Dialog>
)
}
115 changes: 71 additions & 44 deletions packages/dnb-eufemia/src/fragments/drawer-list/DrawerListProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export default class DrawerListProvider extends React.PureComponent {
on_resize,
page_offset,
observer_element,
direction: directionProp,
} = this.props

// const skipPortal = isTrue(skip_portal)
Expand All @@ -260,61 +261,87 @@ export default class DrawerListProvider extends React.PureComponent {
const spaceToTopOffset = 2 * 16
const spaceToBottomOffset = 2 * 16
const elem = this.state.wrapper_element || this._refRoot.current
const getSpaceToBottom = ({ rootElem, pageYOffset }) => {
const spaceToBottom =
rootElem.clientHeight -
(getOffsetTop(elem) + elem.offsetHeight) +
pageYOffset

const html = document.documentElement
if (spaceToBottom < customMinHeight && rootElem !== html) {
return getSpaceToBottom({
rootElem: html,
pageYOffset,
})
}

const renderDirection = () => {
try {
// make calculation for both direction and height
const rootElem = customElem || document.documentElement

const pageYOffset = !isNaN(parseFloat(page_offset))
? parseFloat(page_offset)
: rootElem.scrollTop /* pageYOffset */
const spaceToTop =
getOffsetTop(elem) + elem.offsetHeight - pageYOffset
const spaceToBottom =
rootElem.clientHeight /* innerHeight */ -
(getOffsetTop(elem) + elem.offsetHeight) +
pageYOffset

const direction =
return spaceToBottom
}

const calculateMaxHeight = () => {
// make calculation for both direction and height
const rootElem = customElem || document.documentElement

const pageYOffset = !isNaN(parseFloat(page_offset))
? parseFloat(page_offset)
: rootElem.scrollTop
const spaceToTop =
getOffsetTop(elem) + elem.offsetHeight - pageYOffset
const spaceToBottom = getSpaceToBottom({ rootElem, pageYOffset })

let direction = directionProp
if (!direction || direction === 'auto') {
direction =
Math.max(spaceToBottom - directionOffset, directionOffset) <
customMinHeight && spaceToTop > customMinHeight
? 'top'
: 'bottom'
}

// make sure we never get higher than we have defined in CSS
let max_height = customMaxHeight
if (!(max_height > 0)) {
max_height =
direction === 'top'
? spaceToTop -
((this.state.wrapper_element || this._refRoot.current)
.offsetHeight || 0) -
spaceToTopOffset
: spaceToBottom - spaceToBottomOffset

// get the view port height, like in CSS
let vh = 0
if (typeof window.visualViewport !== 'undefined') {
vh = window.visualViewport.height
} else {
vh = Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
)
}
// make sure we never get higher than we have defined in CSS
let maxHeight = customMaxHeight
if (!(maxHeight > 0)) {
if (direction === 'top') {
maxHeight =
spaceToTop -
((this.state.wrapper_element || this._refRoot.current)
.offsetHeight || 0) -
spaceToTopOffset
}

// like defined in CSS
vh = vh * (isScrollable ? 0.7 : 0.9)
if (direction === 'bottom') {
maxHeight = spaceToBottom - spaceToBottomOffset
}

if (max_height > vh) {
max_height = vh
}
// get the view port height, like in CSS
let vh = 0
if (typeof window.visualViewport !== 'undefined') {
vh = window.visualViewport.height
} else {
vh = Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
)
}

// like defined in CSS
vh = vh * (isScrollable ? 0.7 : 0.9)

// convert px to rem
max_height = roundToNearest(max_height, 8) / 16
if (maxHeight > vh) {
maxHeight = vh
}

// convert px to rem
maxHeight = roundToNearest(maxHeight, 8) / 16
}

return { direction, maxHeight }
}

const renderDirection = () => {
try {
const { direction, maxHeight: max_height } = calculateMaxHeight()

// update the states
if (this.props.direction === 'auto') {
this.setState({
Expand Down
Loading

0 comments on commit 32b7b5b

Please sign in to comment.