Skip to content

Commit

Permalink
fix: fix #heading level reset issue
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Jun 3, 2020
1 parent 3b9872d commit 74ae44d
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ showTabs: true
| `reset` | _(optional)_ If set to true, the heading level will be reset to 2. You can give it a custom level if you need to, e.g. `reset(1)`. |
| `skip_correction` | _(optional)_ If set to true, the heading will not be corrected and warnings will not be shown. Warnings do not show up in **production builds** else either. |
| `debug` | _(optional)_ If set to true, the content will have a prefix, showing the heading level. |
| `element` | _(optional)_ define what HTML element should be used. Defaults to semantic heading element. |
| `debug_counter` | _(optional)_ If set to true, the content will have both a prefix and a JSON log attached to both headings and level contexts. |
| `element` | _(optional)_ define what HTML element should be used. If you use, e.g. a `span`, then `role="heading"` and `aria-level` gets set. Defaults to semantic heading element. |
| `[heading options]` | _(optional)_ accepts all [heading.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Heading/toLocaleString) options as an object - can also be a JSON given as the parameter e.g. `options='{"minimumFractionDigits":"2"}'`. |
| [Space](/uilib/components/space/properties) | _(optional)_ spacing properties like `top` or `bottom` are supported. |

Expand Down
10 changes: 6 additions & 4 deletions packages/dnb-ui-lib/src/components/heading/Heading.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ export default class Heading extends React.PureComponent {
if (state._listenForPropChanges) {
const level = parseFloat(props.level)
if (
state.prevLevel !== props.level &&
level > 0 &&
level !== state.level
(state.prevLevel !== props.level &&
level > 0 &&
level !== state.level) ||
props.relevel
) {
// Because we do not want to run MakeMeReady to set "this.level = 2"
state.counter.skipMakeMeReady()
Expand All @@ -144,7 +145,7 @@ export default class Heading extends React.PureComponent {
source: props.text || props.children, // only for debuging
debug: props.debug || state.context.heading?.debug
})
state.level = newLevel
state.level = state.prevLevel = newLevel
}
}
state._listenForPropChanges = true
Expand Down Expand Up @@ -210,6 +211,7 @@ export default class Heading extends React.PureComponent {
render() {
const {
text,
relevel: _relevel, // eslint-disable-line
group: _group, // eslint-disable-line
debug: _debug, // eslint-disable-line
debug_counter: _debug_counter, // eslint-disable-line
Expand Down
38 changes: 15 additions & 23 deletions packages/dnb-ui-lib/src/components/heading/HeadingCounter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
// import {
// makeUniqueId
// } from '../../shared/component-helper'
import { globalSyncCounter, globalHeadingCounter } from './HeadingHelpers'
import {
globalSyncCounter,
globalHeadingCounter
// globalNextLevel,
// globalResetNextTime
} from './HeadingHelpers'

export const initCounter = (props = null) => {
if (!globalHeadingCounter.current) {
Expand Down Expand Up @@ -44,10 +49,6 @@ export class Counter {
}

this.children = props.children

// if (parseFloat(props.level) > 0) {
// this.setLevel(props.level)
// }
}

report(...str) {
Expand Down Expand Up @@ -115,27 +116,18 @@ export class Counter {
if (!this.hasCorrection()) {
if (this.contextCounter.level > 1) {
this.level = this.contextCounter.level
// if (this.entry === 0) {
// this.entry = this.level
// }
} else if (this.contextCounter._isReady) {
if (!this.bypassChecks) {
this.level = 2
}
// this.entry = 2
} else if (!this.contextCounter._isReady) {
this.contextCounter._isReady = true
// this._isReady = true // <-- do we need this?
if (!this.bypassChecks) {
this.level = 1
}
// this.entry = 1
}

if (
// !this.isHeading &&
this.entry === 0
) {
if (this.entry === 0) {
this.entry = this.level

if (this.isHeading) {
Expand Down Expand Up @@ -291,16 +283,16 @@ export class Counter {

reset(toLevel = null) {
toLevel = parseFloat(toLevel) || 2

this.level = toLevel
this.entry = 0
this._isReady = false
this.entry = toLevel

if (
toLevel === 1 &&
!this.isInContext() &&
!globalHeadingCounter.current?.hasEntryLevel()
) {
globalHeadingCounter.current?.setEntryLevel()
if (this.contextCounter) {
this.contextCounter.level = this.contextCounter.entry
}

if (toLevel === 1 && globalHeadingCounter.current) {
globalHeadingCounter.current.level = 2
}
}
}
7 changes: 5 additions & 2 deletions packages/dnb-ui-lib/src/components/heading/HeadingHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ export const correctHeadingLevel = ({
update(level)
counter.disableBypassChecks()
} else if (globalResetNextTime.current > 0) {
counter.reset(globalResetNextTime.current)
const resetLevel = globalResetNextTime.current
globalResetNextTime.current = null
update(level)
counter.makeMeReady()
counter.reset(resetLevel)
} else if (
reset === true ||
reset === 'true' ||
Expand Down Expand Up @@ -123,10 +124,12 @@ export function resetAllLevels() {
export const globalResetNextTime = React.createRef(false)
export function resetLevels(level = 1) {
globalResetNextTime.current = level
globalNextLevel.current = null
}
export const globalNextLevel = React.createRef(null)
export function setNextLevel(level) {
globalNextLevel.current = parseFloat(level)
globalResetNextTime.current = null
}

let countHeadings = 0
Expand Down
42 changes: 33 additions & 9 deletions packages/dnb-ui-lib/src/components/heading/HeadingProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,44 @@ export default class HeadingProvider extends React.PureComponent {
static contextType = HeadingContext
// static contextType = Context// in order to get newProps, we use HeadingContext instead

// static getDerivedStateFromProps(props, state) {
// if (state._listenForPropChanges) {
// }
// state._listenForPropChanges = true

// return state
// }
static getDerivedStateFromProps(props, state) {
if (state._listenForPropChanges) {
const level = parseFloat(props.level)
if (
(state.prevLevel !== props.level &&
level > 0 &&
level !== state.level) ||
props.relevel
) {
// Because we do not want to run MakeMeReady to set "this.level = 2"
// state.counter.skipMakeMeReady()

// Run this again here, so we can get a recalculated "useLevel" from the counter
const { level: newLevel } = correctHeadingLevel({
counter: state.counter,
level,
// reset: props.reset,
bypassChecks:
isTrue(props.skip_correction) ||
isTrue(state.context.heading?.skip_correction),
source: props.text || props.children, // only for debuging
debug: props.debug || state.context.heading?.debug
})
state.level = state.prevLevel = newLevel
}
state._listenForPropChanges = true

return state
}
}

constructor(props, context) {
super(props)

// this._id = props.id || makeUniqueId()

const state = {
context,
_listenForPropChanges: true
}

Expand All @@ -105,7 +129,7 @@ export default class HeadingProvider extends React.PureComponent {
state.counter.setContextCounter(globalHeadingCounter.current)
}

state.counter.rerender = this.rerender
// state.counter.rerender = this.rerender

const { level: newLevel } = correctHeadingLevel({
counter: state.counter,
Expand All @@ -125,7 +149,7 @@ export default class HeadingProvider extends React.PureComponent {
// This will require a new Counter "group" - not the global.
// We basically start again counting from this one.
state.level = newLevel
state.initLevel = state.newProps.level || newLevel
state.prevLevel = state.newProps.level || newLevel
this.state = state
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
loadScss
} from '../../../core/jest/jestSetup'
import Heading from '../Heading'
// import{ resetLevels, resetAllLevels } from '../Heading'
import {
resetLevels,
setNextLevel
// , resetAllLevels
} from '../Heading'
import H3 from '../../../elements/H3'

// just to make sure we re-run the test in watch mode due to changes in theese files
Expand Down Expand Up @@ -191,13 +195,9 @@ describe('Heading component', () => {
it('have to match after level state update', () => {
const warn = jest.fn()

// resetLevels(1)
resetLevels(1)
// resetAllLevels()
const Comp = mount(
<Heading reset={1} debug={warn}>
Heading #1
</Heading>
)
const Comp = mount(<Heading debug={warn}>Heading #1</Heading>)

expect(Comp.find('.dnb-heading').at(0).text()).toBe('[h1] Heading #1')

Expand Down Expand Up @@ -226,6 +226,45 @@ describe('Heading component', () => {
expect(warn).toBeCalledTimes(1) // still one time, same as we had earlier
})

it('have to have correct leveling after using setNextLevel', () => {
setNextLevel(4)

resetLevels(1)
const Comp1 = mount(<Heading debug={warn}>h1</Heading>)

setNextLevel(2)
const Comp2 = mount(<Heading debug={warn}>h2</Heading>)

setNextLevel(3)
const Comp3 = mount(
<Heading.Level debug={warn}>
<Heading>h3</Heading>
</Heading.Level>
)

expect(Comp1.find('.dnb-heading').at(0).text()).toBe('[h1] h1')
expect(Comp2.find('.dnb-heading').at(0).text()).toBe('[h2] h2')
expect(Comp3.find('.dnb-heading').at(0).text()).toBe('[h3] h3')

Comp2.setState({
level: 4
})
expect(Comp2.find('.dnb-heading').at(0).text()).toBe('[h4] h2')

resetLevels(1)
Comp2.setProps({ relevel: true })
expect(Comp2.find('.dnb-heading').at(0).text()).toBe('[h1] h2')

setNextLevel(2)
Comp1.setProps({ relevel: true })
expect(Comp1.find('.dnb-heading').at(0).text()).toBe('[h2] h1')

// setNextLevel(4)
// resetLevels(4)
// Comp3.setProps({ relevel: true })
// expect(Comp3.find('.dnb-heading').at(0).text()).toBe('[h4] h3')
})

it('have to have aria role and level if set as span element', () => {
const Comp = mount(
<Heading element="span" debug={warn} reset={1}>
Expand Down Expand Up @@ -280,9 +319,10 @@ describe('Heading component', () => {
})

it('should not increase level above 6', () => {
resetLevels(1)
const Comp = mount(
<>
<Heading.Level debug={warn} reset={1}>
<Heading.Level debug={warn}>
<Heading>Heading #1</Heading>
<Heading.Increase skip_correction level="6">
<Heading>Heading #2</Heading>
Expand Down
19 changes: 15 additions & 4 deletions packages/dnb-ui-lib/stories/components/Headings.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import React from 'react'
import { Wrapper, Box } from '../helpers'
import styled from '@emotion/styled'
import { H2, H3 } from '../../src/elements'
import { ToggleButton } from '../../src/components'
import { ToggleButton, Button } from '../../src/components'
import Provider from '../../src/shared/Provider'
import Heading, {
// resetLevels,
setNextLevel
setNextLevel,
resetLevels
} from '../../src/components/Heading'

const CustomStyle = styled.div`
Expand Down Expand Up @@ -403,8 +403,19 @@ function App() {
const [showHeading3, setShowHeading3] = React.useState(false)
const [showHeading4, setShowHeading4] = React.useState(false)

React.useState(() => {
resetLevels(1)
})

return (
<Heading.Level group="A" debug debug_counter reset={1}>
<Heading.Level
group="A"
debug
debug_counter
// reset={1}
>
<Button text="Reset" size="small" onClick={() => resetLevels(1)} />

<Heading>h1</Heading>
<Heading>h2</Heading>
<Heading increase>h3</Heading>
Expand Down

0 comments on commit 74ae44d

Please sign in to comment.