@dhis2-ui/layer
Advanced tools
Sorry, the diff of this file is not supported yet
| import { Given, Then } from '@badeball/cypress-cucumber-preprocessor' | ||
| Given('a Layer with children is rendered', () => { | ||
| cy.visitStory('Layer', 'Default') | ||
| }) | ||
| Then('the children are visible', () => { | ||
| cy.contains('I am a child').should('be.visible') | ||
| }) |
Sorry, the diff of this file is not supported yet
| import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor' | ||
| Given('a Layer with a button below it is rendered', () => { | ||
| cy.visitStory('Layer', 'Blocking') | ||
| }) | ||
| Given('a Layer with a button in it is rendered', () => { | ||
| cy.visitStory('Layer', 'With Click Handler') | ||
| }) | ||
| When('the user clicks the button', () => { | ||
| cy.get('button:contains("Test")').click() | ||
| }) | ||
| When('the user clicks on the layer', () => { | ||
| cy.get('[data-test="dhis2-uicore-layer"]').click() | ||
| }) | ||
| When('the user clicks on the button coordinates', () => { | ||
| cy.getPositionsBySelectors('button').then(([rect]) => { | ||
| // Get button center coordinates | ||
| const buttonCenterX = rect.left + rect.width / 2 | ||
| const buttonCenterY = rect.top + rect.height / 2 | ||
| // click body on the button center | ||
| cy.get('body').click(buttonCenterX, buttonCenterY) | ||
| }) | ||
| }) | ||
| Then('the onClick handler of the button is called', () => { | ||
| cy.window().should((win) => { | ||
| expect(win.onButtonClick).to.be.calledOnce | ||
| }) | ||
| }) | ||
| Then('the onClick handler of the layer is called', () => { | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.be.calledOnce | ||
| }) | ||
| }) | ||
| Then('the onClick handler of the button is not called', () => { | ||
| cy.window().should((win) => { | ||
| expect(win.onButtonClick).to.have.callCount(0) | ||
| }) | ||
| }) | ||
| Then('the onClick handler of the layer is not called', () => { | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.have.callCount(0) | ||
| }) | ||
| }) |
Sorry, the diff of this file is not supported yet
| import { Given, Then } from '@badeball/cypress-cucumber-preprocessor' | ||
| Given('two equal sibling Layers are rendered', () => { | ||
| cy.visitStory('Layer', 'Equal Siblings') | ||
| }) | ||
| Given( | ||
| 'an alert, blocking, and applicatioTop Layer are rendered as siblings', | ||
| () => { | ||
| cy.visitStory('Layer', 'Inequal Siblings') | ||
| } | ||
| ) | ||
| Given('a blocking layer is rendered as the child of an alert layer', () => { | ||
| cy.visitStory('Layer', 'Nested Lower Levels') | ||
| }) | ||
| Given('an alert layer is rendered as the child of a blocking layer', () => { | ||
| cy.visitStory('Layer', 'Nested Higher Levels') | ||
| }) | ||
| Given( | ||
| 'a layer with level 1001 is a sibling of 3 nested layers with level 1000', | ||
| () => { | ||
| cy.visitStory('Layer', 'Levels Are Respected When Nesting') | ||
| } | ||
| ) | ||
| Given( | ||
| 'an applicatioTop layer with a nested alert layer with a blocking sibling', | ||
| () => { | ||
| cy.visitStory('Layer', 'Nested Higher Level Ends On Top') | ||
| } | ||
| ) | ||
| Then('the second layer is on top of the first layer', () => { | ||
| // Wouldn't work if the element wasn't ontop of the second layer. | ||
| // Cypress would fail, stating: | ||
| // "[...] is being covered by another element: [...]" | ||
| cy.get('.backdrop:visible').click() | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.be.calledOnce | ||
| expect(win.onLayerClick).to.be.calledWith('second') | ||
| }) | ||
| }) | ||
| Then('the alert layer is on top', () => { | ||
| cy.get('.backdrop:visible').click() | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.be.calledOnce | ||
| expect(win.onLayerClick).to.be.calledWith('alert') | ||
| }) | ||
| }) | ||
| Then('the layer with level 1001 is on top', () => { | ||
| cy.get('.backdrop:visible').click() | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.be.calledOnce | ||
| expect(win.onLayerClick).to.be.calledWith('1001') | ||
| }) | ||
| }) | ||
| Then('the blocking layer is on top', () => { | ||
| cy.get('.backdrop:visible').click() | ||
| cy.window().should((win) => { | ||
| expect(win.onLayerClick).to.be.calledOnce | ||
| expect(win.onLayerClick).to.be.calledWith('blocking') | ||
| }) | ||
| }) | ||
| Then('the blocking layer is a child of the alert layer', () => { | ||
| cy.get('[data-test="blocking"]') | ||
| .parent() | ||
| .should('have.data', 'test', 'alert') | ||
| }) | ||
| Then('the alert layer is a sibling of the blocking layer', () => { | ||
| cy.get('[data-test="blocking"]').next().should('have.data', 'test', 'alert') | ||
| }) |
| export { Layer } from './layer.js' | ||
| // DEPRECATED: Remove in 7.0.0 | ||
| export { useLayerContext } from './use-layer-context.js' |
| import { createContext } from 'react' | ||
| export const LayerContext = createContext({ | ||
| node: document.body, | ||
| level: 0, | ||
| }) | ||
| export const { Provider, Consumer } = LayerContext |
| import { layers } from '@dhis2/ui-constants' | ||
| import React from 'react' | ||
| import { Layer } from './layer.js' | ||
| window.onButtonClick = window.Cypress && window.Cypress.cy.stub() | ||
| window.onLayerClick = window.Cypress && window.Cypress.cy.stub() | ||
| const createNamedLayerClick = (name) => () => { | ||
| window.onLayerClick(name) | ||
| } | ||
| export default { title: 'Layer', component: Layer } | ||
| export const Default = () => ( | ||
| <Layer> | ||
| <p>I am a child</p> | ||
| </Layer> | ||
| ) | ||
| export const Blocking = () => ( | ||
| <> | ||
| <button onClick={window.onButtonClick}>Test</button> | ||
| <Layer /> | ||
| </> | ||
| ) | ||
| export const WithClickHandler = () => ( | ||
| <Layer onBackdropClick={window.onLayerClick}> | ||
| <button onClick={window.onButtonClick}>Test</button> | ||
| </Layer> | ||
| ) | ||
| export const EqualSiblings = () => ( | ||
| <> | ||
| <Layer onBackdropClick={createNamedLayerClick('first')} /> | ||
| <Layer onBackdropClick={createNamedLayerClick('second')} /> | ||
| </> | ||
| ) | ||
| export const InequalSiblings = () => ( | ||
| <> | ||
| <Layer | ||
| level={layers.alert} | ||
| onBackdropClick={createNamedLayerClick('alert')} | ||
| /> | ||
| <Layer | ||
| level={layers.blocking} | ||
| onBackdropClick={createNamedLayerClick('blocking')} | ||
| /> | ||
| <Layer | ||
| level={layers.applicationTop} | ||
| onBackdropClick={createNamedLayerClick('applicationTop')} | ||
| /> | ||
| </> | ||
| ) | ||
| export const NestedLowerLevels = () => ( | ||
| <Layer | ||
| level={layers.alert} | ||
| dataTest="alert" | ||
| onBackdropClick={createNamedLayerClick('alert')} | ||
| > | ||
| <Layer | ||
| level={layers.blocking} | ||
| dataTest="blocking" | ||
| disablePortal={true} | ||
| onBackdropClick={createNamedLayerClick('blocking')} | ||
| /> | ||
| </Layer> | ||
| ) | ||
| export const NestedHigherLevels = () => ( | ||
| <Layer | ||
| level={layers.blocking} | ||
| dataTest="blocking" | ||
| onBackdropClick={createNamedLayerClick('blocking')} | ||
| > | ||
| <Layer | ||
| level={layers.alert} | ||
| dataTest="alert" | ||
| onBackdropClick={createNamedLayerClick('alert')} | ||
| /> | ||
| </Layer> | ||
| ) | ||
| export const LevelsAreRespectedWhenNesting = () => ( | ||
| <> | ||
| <Layer level={1000}> | ||
| <Layer level={1000}> | ||
| <Layer | ||
| level={1000} | ||
| onBackdropClick={createNamedLayerClick('1000')} | ||
| /> | ||
| </Layer> | ||
| </Layer> | ||
| <Layer level={1001} onBackdropClick={createNamedLayerClick('1001')} /> | ||
| </> | ||
| ) | ||
| export const NestedHigherLevelEndsOnTop = () => ( | ||
| <> | ||
| <Layer level={layers.applicationTop}> | ||
| <Layer | ||
| level={layers.alert} | ||
| onBackdropClick={createNamedLayerClick('alert')} | ||
| /> | ||
| </Layer> | ||
| <Layer | ||
| level={layers.blocking} | ||
| onBackdropClick={createNamedLayerClick('blocking')} | ||
| /> | ||
| </> | ||
| ) |
+90
| import { deprecated } from '@dhis2/prop-types' | ||
| import { Portal } from '@dhis2-ui/portal' | ||
| import cx from 'classnames' | ||
| import PropTypes from 'prop-types' | ||
| import React from 'react' | ||
| const Layer = ({ | ||
| children, | ||
| className, | ||
| dataTest = 'dhis2-uicore-layer', | ||
| disablePortal, | ||
| level = 'auto', | ||
| onBackdropClick, | ||
| onClick, | ||
| position = 'fixed', | ||
| translucent, | ||
| }) => { | ||
| const resolvedOnClick = onBackdropClick || onClick | ||
| return ( | ||
| <Portal disable={disablePortal}> | ||
| <div | ||
| className={cx('layer', className, position, { | ||
| translucent, | ||
| })} | ||
| data-test={dataTest} | ||
| > | ||
| {resolvedOnClick && ( | ||
| <div | ||
| className="backdrop" | ||
| onClick={(event) => resolvedOnClick({}, event)} | ||
| /> | ||
| )} | ||
| {children} | ||
| <style jsx>{` | ||
| div { | ||
| z-index: ${level}; | ||
| } | ||
| `}</style> | ||
| <style jsx>{` | ||
| div { | ||
| inset-block-start: 0; | ||
| inset-inline-start: 0; | ||
| min-height: 100vh; | ||
| min-width: 100vw; | ||
| } | ||
| div.fixed { | ||
| position: fixed; | ||
| height: 100vh; | ||
| width: 100vw; | ||
| } | ||
| div.absolute { | ||
| position: absolute; | ||
| height: 100%; | ||
| width: 100%; | ||
| } | ||
| div.translucent { | ||
| background-color: rgba(33, 43, 54, 0.4); | ||
| } | ||
| div.backdrop { | ||
| position: absolute; | ||
| inset: 0; | ||
| z-index: -1; | ||
| } | ||
| `}</style> | ||
| </div> | ||
| </Portal> | ||
| ) | ||
| } | ||
| Layer.propTypes = { | ||
| children: PropTypes.node, | ||
| className: PropTypes.string, | ||
| dataTest: PropTypes.string, | ||
| /** Disable the Portal, useful for nesting layers */ | ||
| disablePortal: PropTypes.bool, | ||
| /** Z-index level */ | ||
| level: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), | ||
| position: PropTypes.oneOf(['absolute', 'fixed']), | ||
| /** Adds a semi-transparent background */ | ||
| translucent: PropTypes.bool, | ||
| /** Backdrop click handler */ | ||
| onBackdropClick: PropTypes.func, | ||
| /** Click handler - DEPRECATED */ | ||
| onClick: deprecated(PropTypes.func, 'Please use "onBackdropClick" instead'), | ||
| } | ||
| export { Layer } |
| import { Center } from '@dhis2-ui/center' | ||
| import { CircularLoader } from '@dhis2-ui/loader' | ||
| import React from 'react' | ||
| import { Layer } from './layer.js' | ||
| const description = ` | ||
| Layers are used for creating different levels of stacking of interface elements. | ||
| See more about stacking guidelines at the [design system](https://github.com/dhis2/design-system/blob/master/principles/layout.md#stacking). | ||
| Layers are used in Modals, Popovers, and Alerts. | ||
| \`\`\`js | ||
| import { Layer } from '@dhis2/ui' | ||
| \`\`\` | ||
| _**Note:** These demos may take some time to load._ | ||
| ` | ||
| export default { | ||
| title: 'Layer', | ||
| component: Layer, | ||
| /** | ||
| * `inlineStories: false` renders these layers in iframes instead of inline. | ||
| * This fixes an issue where all the layers on the docs page render on top | ||
| * of eachother, each covering the whole screen. | ||
| * There is a performance tradeof, and they are slow to load. | ||
| */ | ||
| parameters: { | ||
| docs: { | ||
| inlineStories: false, | ||
| iframeHeight: '180px', | ||
| description: { component: description }, | ||
| }, | ||
| }, | ||
| // Handle weird treatment of non-literal defaultProps (see Transfer.stories) | ||
| args: { | ||
| position: 'fixed', | ||
| dataTest: 'dhis2-uicore-layer', | ||
| level: 'auto', | ||
| }, | ||
| } | ||
| const Template = (args) => ( | ||
| <> | ||
| <Layer {...args} /> | ||
| <h1>Text behind the layer</h1> | ||
| <p>Lorem ipsum</p> | ||
| </> | ||
| ) | ||
| export const Default = Template.bind({}) | ||
| export const Translucent = Template.bind({}) | ||
| Translucent.args = { translucent: true } | ||
| export const WithOnBackdropClick = Template.bind({}) | ||
| WithOnBackdropClick.args = { | ||
| onBackdropClick: () => alert('layer backdrop was clicked'), | ||
| } | ||
| export const WithCenteredContentCircularLoader = Template.bind({}) | ||
| WithCenteredContentCircularLoader.args = { | ||
| children: ( | ||
| <Center> | ||
| <CircularLoader /> | ||
| </Center> | ||
| ), | ||
| } |
| import { useContext } from 'react' | ||
| import { LayerContext } from './layer-context.js' | ||
| export const useLayerContext = () => useContext(LayerContext) |
+5
-4
| { | ||
| "name": "@dhis2-ui/layer", | ||
| "version": "10.16.2", | ||
| "version": "10.16.3-alpha.1", | ||
| "description": "UI Layer", | ||
@@ -36,4 +36,4 @@ "repository": { | ||
| "@dhis2/prop-types": "^3.1.2", | ||
| "@dhis2-ui/portal": "10.16.2", | ||
| "@dhis2/ui-constants": "10.16.2", | ||
| "@dhis2-ui/portal": "10.16.3-alpha.1", | ||
| "@dhis2/ui-constants": "10.16.3-alpha.1", | ||
| "classnames": "^2.3.1", | ||
@@ -44,3 +44,4 @@ "prop-types": "^15.7.2" | ||
| "build", | ||
| "types" | ||
| "types", | ||
| "src" | ||
| ], | ||
@@ -47,0 +48,0 @@ "devDependencies": { |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
50120
41.11%39
44.44%1051
54.56%1
Infinity%+ Added
+ Added
- Removed
- Removed