Skip to content

Commit 1fbb31c

Browse files
use custom stay-open dropdowns
1 parent 8b45059 commit 1fbb31c

File tree

2 files changed

+137
-32
lines changed

2 files changed

+137
-32
lines changed

src/PivotTableUI.jsx

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,51 @@ DraggableAttribute.propTypes = {
141141
zIndex: PropTypes.number
142142
};
143143

144+
class Dropdown extends React.PureComponent {
145+
146+
render() {
147+
return <div className="pvtDropdown" style={{zIndex: this.props.zIndex}}>
148+
<div onClick={e => {
149+
e.stopPropagation();
150+
this.props.toggle();
151+
}}
152+
className={'pvtDropdownValue pvtDropdownCurrent ' +
153+
(this.props.open ? 'pvtDropdownCurrentOpen' : '') }
154+
role="button"
155+
>
156+
<div className="pvtDropdownIcon">
157+
{this.props.open ? '×' : '▾'}
158+
</div>
159+
{this.props.current || <span>&nbsp;</span> }
160+
</div>
161+
162+
{this.props.open &&
163+
<div className="pvtDropdownMenu">
164+
{this.props.values.map(r => <div key={r} role="button"
165+
onClick={e => {
166+
e.stopPropagation();
167+
if (this.props.current === r) {
168+
this.props.toggle();
169+
}
170+
else { this.props.setValue(r); }
171+
}}
172+
className={'pvtDropdownValue ' +
173+
(r === this.props.current ? 'pvtDropdownActiveValue' : '')}
174+
>{r}</div>
175+
)}
176+
</div> }
177+
</div>;
178+
}
179+
}
144180

145181

146182
class PivotTableUI extends React.PureComponent {
147183
constructor(props) {
148184
super(props);
149-
this.state = {unusedOrder: [], zIndices: {}, maxZIndex: 1000};
185+
this.state = {
186+
unusedOrder: [], zIndices: {}, maxZIndex: 1000,
187+
openDropdown: false
188+
};
150189
}
151190

152191
componentWillMount() {
@@ -221,6 +260,10 @@ class PivotTableUI extends React.PureComponent {
221260
}));
222261
}
223262

263+
isOpen(dropdown) {
264+
return this.state.openDropdown === dropdown;
265+
}
266+
224267
makeDnDCell(items, onChange, classes) {
225268
return <Sortable
226269
options={{
@@ -250,13 +293,15 @@ class PivotTableUI extends React.PureComponent {
250293
this.props.rendererName : Object.keys(this.props.renderers)[0];
251294

252295
const rendererCell = <td className="pvtRenderers">
253-
<select value={rendererName}
254-
onChange={({target: {value}}) =>
255-
this.propUpdater('rendererName')(value)}
256-
>
257-
{Object.keys(this.props.renderers)
258-
.map(r => <option value={r} key={r}>{r}</option>)}
259-
</select>
296+
<Dropdown
297+
current={rendererName}
298+
values={Object.keys(this.props.renderers)}
299+
open={this.isOpen('renderer')}
300+
zIndex={this.isOpen('renderer') ? this.state.maxZIndex + 1 : 1}
301+
toggle={() => this.setState({openDropdown:
302+
this.isOpen('renderer') ? false : 'renderer'})}
303+
setValue={this.propUpdater('rendererName')}
304+
/>
260305
</td>;
261306

262307
const sortIcons = {
@@ -266,13 +311,16 @@ class PivotTableUI extends React.PureComponent {
266311
};
267312

268313
const aggregatorCell = <td className="pvtVals">
269-
<select value={this.props.aggregatorName}
270-
onChange={({target: {value}}) =>
271-
this.propUpdater('aggregatorName')(value)}
272-
>
273-
{Object.keys(this.props.aggregators).map(n =>
274-
<option key={`agg${n}`} value={n}>{n}</option>)}
275-
</select>
314+
315+
<Dropdown
316+
current={this.props.aggregatorName}
317+
values={Object.keys(this.props.aggregators)}
318+
open={this.isOpen('aggregators')}
319+
zIndex={this.isOpen('aggregators') ? this.state.maxZIndex + 1 : 1}
320+
toggle={() => this.setState({openDropdown:
321+
this.isOpen('aggregators') ? false : 'aggregators'})}
322+
setValue={this.propUpdater('aggregatorName')}
323+
/>
276324
<a role="button" className="pvtRowOrder" onClick={() =>
277325
this.propUpdater('rowOrder')(sortIcons[this.props.rowOrder].next)}
278326
>
@@ -285,16 +333,21 @@ class PivotTableUI extends React.PureComponent {
285333
</a>
286334
{(numValsAllowed > 0) && <br />}
287335
{new Array(numValsAllowed).fill().map((n, i) =>
288-
<select value={this.props.vals[i]} key={`val${i}`}
289-
onChange={({target: {value}}) =>
290-
this.sendPropUpdate({vals: {$splice: [[i, 1, value]]}})}
291-
>
292-
<option key={`none${i}`} value=""></option>
293-
{Object.keys(this.attrValues).filter(e =>
294-
!this.props.hiddenAttributes.includes(e) &&
295-
!this.props.hiddenFromAggregators.includes(e)).map((v, j) =>
296-
<option key={`${i}-${j}`} value={v}>{v}</option>)}
297-
</select>
336+
[
337+
<Dropdown
338+
current={this.props.vals[i]}
339+
values={Object.keys(this.attrValues).filter(e =>
340+
!this.props.hiddenAttributes.includes(e) &&
341+
!this.props.hiddenFromAggregators.includes(e))}
342+
open={this.isOpen(`val${i}`)}
343+
zIndex={this.isOpen(`val${i}`) ? this.state.maxZIndex + 1 : 1}
344+
toggle={() => this.setState({openDropdown:
345+
this.isOpen(`val${i}`) ? false : `val${i}`})}
346+
setValue={value =>
347+
this.sendPropUpdate({vals: {$splice: [[i, 1, value]]}})}
348+
/>,
349+
i + 1 !== numValsAllowed ? <br /> : null
350+
]
298351
)}
299352
</td>;
300353

@@ -328,14 +381,18 @@ class PivotTableUI extends React.PureComponent {
328381
</td>;
329382

330383
if (horizUnused) {
331-
return <table className="pvtUi"><tbody>
384+
return <table className="pvtUi"><tbody
385+
onClick={() => this.setState({openDropdown: false})}
386+
>
332387
<tr>{rendererCell }{ unusedAttrsCell }</tr>
333388
<tr>{aggregatorCell }{ colAttrsCell }</tr>
334389
<tr>{rowAttrsCell }{ outputCell }</tr>
335390
</tbody></table>;
336391
}
337392

338-
return <table className="pvtUi"><tbody>
393+
return <table className="pvtUi"><tbody
394+
onClick={() => this.setState({openDropdown: false})}
395+
>
339396
<tr>{rendererCell }{ aggregatorCell }{ colAttrsCell }</tr>
340397
<tr>{unusedAttrsCell }{ rowAttrsCell }{ outputCell }</tr>
341398
</tbody></table>;

src/pivottable.css

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ table.pvtTable tbody tr td {
5050
margin-left: 5px;
5151
display: inline-block;
5252
user-select: none;
53+
text-decoration: none !important;
5354
-webkit-user-select: none;
5455
-moz-user-select: none;
5556
-khtml-user-select: none;
@@ -66,17 +67,64 @@ table.pvtTable tbody tr td {
6667

6768

6869
.pvtRenderers {
69-
padding-left: 6px;
70-
padding-top: 11px;
71-
padding-bottom: 14px;
70+
padding-left: 5px;
71+
user-select: none;
72+
}
73+
74+
.pvtDropdown {
75+
display: inline-block;
76+
position: relative;
77+
-webkit-user-select: none;
78+
-moz-user-select: none;
79+
-khtml-user-select: none;
80+
-ms-user-select: none;
81+
margin: 3px;
82+
}
83+
84+
.pvtDropdownIcon {
85+
float: right;
86+
color: #A2B1C6;
87+
}
88+
.pvtDropdownCurrent {
89+
text-align: left;
90+
border: 1px solid #A2B1C6;
91+
border-radius: 4px;
92+
display: inline-block;
93+
position: relative;
94+
width: 210px;
95+
box-sizing: border-box;
96+
background: white;
97+
}
98+
99+
.pvtDropdownCurrentOpen {
100+
border-radius: 4px 4px 0 0;
101+
}
102+
103+
.pvtDropdownMenu {
104+
background: white;
105+
position: absolute;
106+
width: 100%;
107+
margin-top: -1px;
108+
border-radius: 0 0 4px 4px;
109+
border: 1px solid #A2B1C6;
110+
border-top: 1px solid #DFE8F3;
111+
box-sizing: border-box;
112+
}
113+
114+
.pvtDropdownValue {
115+
padding: 2px 5px;
116+
font-size: 12px;
117+
text-align: left;
118+
}
119+
.pvtDropdownActiveValue {
120+
background: #EBF0F8;
72121
}
73122

74123
.pvtVals {
75124
text-align: center;
76125
white-space: nowrap;
77126
vertical-align: top;
78-
padding-top: 10px;
79-
padding-bottom: 14px;
127+
padding-bottom: 12px;
80128
}
81129

82130
.pvtRows { height: 35px; }

0 commit comments

Comments
 (0)