Skip to content

Commit

Permalink
fix: Prefix instance id in case of custom node id
Browse files Browse the repository at this point in the history
Fixes #315
  • Loading branch information
mrchief committed Jan 19, 2020
1 parent f4ce73c commit a100034
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 19 deletions.
9 changes: 3 additions & 6 deletions src/tag/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import React, { PureComponent } from 'react'

import './index.css'

export const getTagId = id => `${id}_tag`

class Tag extends PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
Expand Down Expand Up @@ -37,10 +35,9 @@ class Tag extends PureComponent {
}

render() {
const { id, label, labelRemove = 'Remove', readOnly, disabled } = this.props

const tagId = getTagId(id)
const buttonId = `${id}_button`
const { label, labelRemove = 'Remove', readOnly, disabled, getDOMId } = this.props
const tagId = getDOMId('tag')
const buttonId = getDOMId('button')
const className = ['tag-remove', readOnly && 'readOnly', disabled && 'disabled'].filter(Boolean).join(' ')
const isDisabled = readOnly || disabled

Expand Down
3 changes: 2 additions & 1 deletion src/tags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import './index.css'

const getTags = (tags = [], onDelete, readOnly, disabled, labelRemove) =>
tags.map(tag => {
const { _id, label, tagClassName, dataset } = tag
const { _id, label, tagClassName, dataset, getDOMId } = tag
return (
<li
className={['tag-item', tagClassName].filter(Boolean).join(' ')}
Expand All @@ -21,6 +21,7 @@ const getTags = (tags = [], onDelete, readOnly, disabled, labelRemove) =>
readOnly={readOnly}
disabled={disabled}
labelRemove={labelRemove}
getDOMId={getDOMId}
/>
</li>
)
Expand Down
14 changes: 4 additions & 10 deletions src/tree-manager/flatten-tree.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import getPartialState from './getPartialState'
import Node from './node'

import { isEmpty } from '../utils'

Expand Down Expand Up @@ -216,16 +217,8 @@ function walkNodes({
_rv = { list: new Map(), defaultValues: [], singleSelectedNode: null },
}) {
const single = simple || radio
nodes.forEach((node, i) => {
node._depth = depth

if (parent) {
node._id = node.id || `${parent._id}-${i}`
node._parent = parent._id
parent._children.push(node._id)
} else {
node._id = node.id || `${rootPrefixId ? `${rootPrefixId}-${i}` : i}`
}
nodes.forEach((n, i) => {
const node = new Node({ rootPrefixId, depth, parent, index: i, ...n })

if (single && node.checked) {
if (_rv.singleSelectedNode) {
Expand Down Expand Up @@ -261,6 +254,7 @@ function walkNodes({
radio,
showPartialState,
hierarchical,
rootPrefixId,
_rv,
})

Expand Down
48 changes: 48 additions & 0 deletions src/tree-manager/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Represents a tree node (not DOM node) in the data tree.
* It can have the following properties:
*
* id {string|optional} User defined id, comes from `data` passed to the component.
* _id {string} Internal id, auto generated if `id` is not defined, otherwise set to `id`.
* rootPrefixId {string} The id of the component's instance.
* parent {Node} Parent node, if a child.
* label {string|required} Checkbox label
* value {string|required} Checkbox value
* children {array<node>|optional} Array of child nodes
* checked {bool|optional} Initial state of checkbox. if true, checkbox is selected and corresponding pill is rendered.
* disabled {bool|optional} Selectable state of checkbox. if true, the checkbox is disabled and the node is not selectable.
* expanded {bool|optional} If true, the node is expanded (children of children nodes are not expanded by default unless children nodes also have expanded: true).
* className {string|optional} Additional css class for the node. This is helpful to style the nodes your way
* tagClassName {string|optional} Css class for the corresponding tag. Use this to add custom style the pill corresponding to the node.
* actions {array<object>|optional} An array of extra action on the node (such as displaying an info icon or any custom icons/elements)
* dataset {object|optional} Allows data-* attributes to be set on the node and tag elements
* isDefaultValue {bool|optional} Indicate if a node is a default value. When true, the dropdown will automatically select the node(s) when there is no other selected node. Can be used on more than one node.
*
*/
export default class Node {
constructor({ depth, rootPrefixId, parent, index, ...dataProps }) {
// first copy all props coming from data
Object.assign(this, dataProps)

// then assign basic ones
this._depth = depth
this.rootPrefixId = rootPrefixId

if (parent) {
this._id = this.id || `${parent._id}-${index}`
this._parent = parent._id
parent._children.push(this._id)
} else {
this._id = this.id || `${rootPrefixId ? `${rootPrefixId}-${index}` : index}`
}
}

/**
* Given an element, generate a DOM Id that's unique across instances
*/
getDOMId = element => {
// if user has defined id, then ensure it's unique across instances
if (this.id) return `${this.rootPrefixId}_${this.id}_${element}`
return `${this._id}_${element}`
}
}
3 changes: 1 addition & 2 deletions src/trigger/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'

import { getAriaLabel } from '../a11y'
import { getTagId } from '../tag'

class Trigger extends PureComponent {
static propTypes = {
Expand All @@ -28,7 +27,7 @@ class Trigger extends PureComponent {
labelledBy.push(triggerId)
}
tags.forEach(t => {
labelledBy.push(getTagId(t._id))
labelledBy.push(t.getDOMId('tag'))
})
labelAttributes = getAriaLabel(texts.label, labelledBy.join(' '))
}
Expand Down

0 comments on commit a100034

Please sign in to comment.