Skip to content

Commit 9dc0094

Browse files
committed
Add dynamic constraint secondary values with story for constraint options
1 parent 9020dbd commit 9dc0094

File tree

7 files changed

+187
-54
lines changed

7 files changed

+187
-54
lines changed

dist/index.js

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,6 +2283,19 @@ var generateClassesForConstraint = function generateClassesForConstraint(prefix,
22832283
return [prefix + '--popover-primary-' + constraint.popover.primary, prefix + '--popover-secondary-' + constraint.popover.secondary, prefix + '--attachment-primary-' + constraint.attachment.primary, prefix + '--attachment-secondary-' + constraint.attachment.secondary];
22842284
};
22852285

2286+
var generatePossibleConstraintsFor = function generatePossibleConstraintsFor(side) {
2287+
switch (side) {
2288+
case 'top':
2289+
case 'bottom':
2290+
return [side + ' left', side + ' center', side + ' right'];
2291+
case 'left':
2292+
case 'right':
2293+
return [side + ' top', side + ' center', side + ' bottom'];
2294+
default:
2295+
return [side.join(' ')];
2296+
}
2297+
};
2298+
22862299
var Positioner = function () {
22872300
function Positioner(options) {
22882301
_classCallCheck(this, Positioner);
@@ -2464,34 +2477,59 @@ var Positioner = function () {
24642477
}, {
24652478
key: 'parseConstraints',
24662479
value: function parseConstraints() {
2467-
var id = 0;
2468-
var classPrefix = this.options.classPrefix;
2480+
var _this = this;
24692481

2470-
this.constraints = this.options.constraints.map(function (constraint) {
2471-
var attachmentConstraint = constraint.attachment.split(' ');
2472-
var popoverConstraint = constraint.popover.split(' ');
2473-
2474-
id += 1;
2475-
2476-
var parsedConstraint = {
2477-
id: id,
2478-
attachment: {
2479-
primary: attachmentConstraint[0],
2480-
secondary: attachmentConstraint[1],
2481-
string: constraint.attachment
2482-
},
2483-
popover: {
2484-
primary: popoverConstraint[0],
2485-
secondary: popoverConstraint[1],
2486-
string: constraint.popover
2487-
}
2488-
};
2482+
this.constraints = [];
2483+
2484+
this.options.constraints.forEach(function (constraint) {
2485+
return _this.parseConstraint(constraint);
2486+
});
2487+
}
2488+
}, {
2489+
key: 'parseConstraint',
2490+
value: function parseConstraint(constraint) {
2491+
var _this2 = this;
2492+
2493+
var validConstraints = [];
24892494

2490-
parsedConstraint.classes = generateClassesForConstraint(classPrefix, parsedConstraint);
2495+
var attachmentConstraints = generatePossibleConstraintsFor(constraint.attachment);
2496+
var popoverConstraints = generatePossibleConstraintsFor(constraint.popover);
24912497

2492-
return Object.assign({}, constraint, parsedConstraint);
2498+
popoverConstraints.forEach(function (attachment) {
2499+
attachmentConstraints.forEach(function (popover) {
2500+
validConstraints.push({ popover: popover, attachment: attachment });
2501+
});
2502+
});
2503+
2504+
validConstraints.forEach(function (validConstraint) {
2505+
return _this2.addConstraint(validConstraint);
24932506
});
24942507
}
2508+
}, {
2509+
key: 'addConstraint',
2510+
value: function addConstraint(constraint) {
2511+
var classPrefix = this.options.classPrefix;
2512+
var attachmentConstraint = constraint.attachment.split(' ');
2513+
var popoverConstraint = constraint.popover.split(' ');
2514+
2515+
var parsedConstraint = {
2516+
id: this.constraints.length,
2517+
attachment: {
2518+
primary: attachmentConstraint[0],
2519+
secondary: attachmentConstraint[1],
2520+
string: constraint.attachment
2521+
},
2522+
popover: {
2523+
primary: popoverConstraint[0],
2524+
secondary: popoverConstraint[1],
2525+
string: constraint.popover
2526+
}
2527+
};
2528+
2529+
parsedConstraint.classes = generateClassesForConstraint(classPrefix, parsedConstraint);
2530+
2531+
this.constraints.push(Object.assign({}, constraint, parsedConstraint));
2532+
}
24952533
}, {
24962534
key: 'enable',
24972535
value: function enable() {
@@ -2551,7 +2589,7 @@ var Positioner = function () {
25512589
}, {
25522590
key: 'destroy',
25532591
value: function destroy() {
2554-
this.clearActiveConstraint();
2592+
// this.clearActiveConstraint();
25552593
this.destroyListeners();
25562594
this.destroyContainer();
25572595
}
@@ -2611,14 +2649,14 @@ var Positioner = function () {
26112649
}, {
26122650
key: 'getActiveConstraint',
26132651
value: function getActiveConstraint() {
2614-
var _this = this;
2652+
var _this3 = this;
26152653

26162654
if (!this.options.unnecessaryRepositioning && this.canFitInto(this.activeConstraint)) {
26172655
return this.activeConstraint;
26182656
}
26192657

26202658
return this.constraints.find(function (constraint) {
2621-
if (_this.canFitInto(constraint)) {
2659+
if (_this3.canFitInto(constraint)) {
26222660
return constraint;
26232661
}
26242662
return false;
@@ -2835,6 +2873,7 @@ var Positioner = function () {
28352873
return;
28362874
}
28372875

2876+
this.toggleActiveConstraints(false);
28382877
this.activeConstraint = null;
28392878
}
28402879
}, {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "popover.js",
3-
"version": "0.2.30",
3+
"version": "0.2.31",
44
"description": "",
55
"main": "dist/index.js",
66
"scripts": {

src/positioner.js

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ const generateClassesForConstraint = (prefix, constraint) => ([
5656
`${prefix}--attachment-secondary-${constraint.attachment.secondary}`,
5757
]);
5858

59+
const generatePossibleConstraintsFor = (side) => {
60+
switch (side) {
61+
case 'top':
62+
case 'bottom':
63+
return [`${side} left`, `${side} center`, `${side} right`];
64+
case 'left':
65+
case 'right':
66+
return [`${side} top`, `${side} center`, `${side} bottom`];
67+
default:
68+
return [side.join(' ')];
69+
}
70+
};
71+
5972
class Positioner {
6073
constructor(options) {
6174
this.generateOptions(options);
@@ -210,33 +223,48 @@ class Positioner {
210223
}
211224

212225
parseConstraints() {
213-
let id = 0;
214-
const classPrefix = this.options.classPrefix;
226+
this.constraints = [];
215227

216-
this.constraints = this.options.constraints.map((constraint) => {
217-
const attachmentConstraint = constraint.attachment.split(' ');
218-
const popoverConstraint = constraint.popover.split(' ');
219-
220-
id += 1;
221-
222-
const parsedConstraint = {
223-
id,
224-
attachment: {
225-
primary: attachmentConstraint[0],
226-
secondary: attachmentConstraint[1],
227-
string: constraint.attachment,
228-
},
229-
popover: {
230-
primary: popoverConstraint[0],
231-
secondary: popoverConstraint[1],
232-
string: constraint.popover,
233-
},
234-
};
235-
236-
parsedConstraint.classes = generateClassesForConstraint(classPrefix, parsedConstraint);
237-
238-
return Object.assign({}, constraint, parsedConstraint);
228+
this.options.constraints.forEach(constraint => this.parseConstraint(constraint));
229+
}
230+
231+
parseConstraint(constraint) {
232+
const validConstraints = [];
233+
234+
const attachmentConstraints = generatePossibleConstraintsFor(constraint.attachment);
235+
const popoverConstraints = generatePossibleConstraintsFor(constraint.popover);
236+
237+
popoverConstraints.forEach((attachment) => {
238+
attachmentConstraints.forEach((popover) => {
239+
validConstraints.push({ popover, attachment });
240+
});
239241
});
242+
243+
validConstraints.forEach(validConstraint => this.addConstraint(validConstraint));
244+
}
245+
246+
addConstraint(constraint) {
247+
const classPrefix = this.options.classPrefix;
248+
const attachmentConstraint = constraint.attachment.split(' ');
249+
const popoverConstraint = constraint.popover.split(' ');
250+
251+
const parsedConstraint = {
252+
id: this.constraints.length,
253+
attachment: {
254+
primary: attachmentConstraint[0],
255+
secondary: attachmentConstraint[1],
256+
string: constraint.attachment,
257+
},
258+
popover: {
259+
primary: popoverConstraint[0],
260+
secondary: popoverConstraint[1],
261+
string: constraint.popover,
262+
},
263+
};
264+
265+
parsedConstraint.classes = generateClassesForConstraint(classPrefix, parsedConstraint);
266+
267+
this.constraints.push(Object.assign({}, constraint, parsedConstraint));
240268
}
241269

242270
enable() {
@@ -287,7 +315,7 @@ class Positioner {
287315
}
288316

289317
destroy() {
290-
this.clearActiveConstraint();
318+
// this.clearActiveConstraint();
291319
this.destroyListeners();
292320
this.destroyContainer();
293321
}
@@ -540,6 +568,7 @@ class Positioner {
540568
clearActiveConstraint() {
541569
if (!this.activeConstraint) { return; }
542570

571+
this.toggleActiveConstraints(false);
543572
this.activeConstraint = null;
544573
}
545574

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Description
2+
3+
The constraint option controls how the popover flows around its attachment. The value is a list of objects, each representing a different position that the popover can be in relative to the attachment element. The popover will go over this list and find the first constraint which allows the popover to fit on screen.
4+
5+
Each object is written like such: `{ popover: '$primary $secondary', attachment: '$primary $secondary' }`.
6+
7+
For the popover element, the `$primary` represents the side of the popover where the arrow will be present, and the `$secondary` represents where the arrow sits on the `$primary` side. For instance, the setting of `popover: 'top left'`, will have the arrow on the top left side of the popover.
8+
9+
For the attachment element, the `$primary` represents the side of the attachment element where the popover will sit on, and the `$secondary` represents where the arrow points to on the `$primary` attachment side. For instance, the setting of `attachment: 'right top'`, will put the popover on the right side of the attachment and with the arrow pointing to the top portion of the attachment element.
10+
11+
The valid values for `$primary` and `$secondary` are `[``top``right``bottom``left``center|middle``]`. You can also choose to omit the `$secondary` value, which will auto-fill with the three logical sides that the `$secondary` value can be in (this is done to reduce code length when designing complex constraints).
12+
13+
## Example
14+
15+
```javascript
16+
import { PopoverjsReact } from 'popover.js';
17+
const popoverOptions = {
18+
showOn: ['trigger.click'],
19+
hideOn: ['trigger.click'],
20+
constraintElement: 'scroll',
21+
constraints: [
22+
{ popover: 'right', attachment: 'left' },
23+
{ popover: 'top', attachment: 'bottom' },
24+
{ popover: 'bottom', attachment: 'top' },
25+
{ popover: 'left', attachment: 'bottom' },
26+
],
27+
};
28+
...
29+
<PopoverjsReact popoverOptions={popoverOptions}>
30+
<div className="demo-trigger">I am the trigger</div>
31+
<div className="demo-content">I am the content</div>
32+
</PopoverjsReact>
33+
...
34+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import { withReadme } from 'storybook-readme';
3+
import { storiesOf } from '@storybook/react';
4+
import { PopoverjsReact } from '../../../dist';
5+
import README from './README/constraint_options.md';
6+
7+
const popoverOptions = {
8+
showOn: ['trigger.click'],
9+
hideOn: ['trigger.click'],
10+
constraintElement: 'scroll',
11+
constraints: [
12+
{ popover: 'right', attachment: 'left' },
13+
{ popover: 'top', attachment: 'bottom' },
14+
{ popover: 'bottom', attachment: 'top' },
15+
{ popover: 'left', attachment: 'bottom' },
16+
],
17+
};
18+
19+
storiesOf('React Adapter', module)
20+
.addDecorator(withReadme(README))
21+
.add('Constraint Options', () => (
22+
<div className="constraint-element">
23+
<div className="constraint-element-inner">
24+
<PopoverjsReact popoverOptions={popoverOptions}>
25+
<div className="demo-trigger">I am the trigger</div>
26+
<div className="demo-content">I am the content</div>
27+
</PopoverjsReact>
28+
</div>
29+
</div>
30+
));

storybook/stories/react/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ import './body_attached';
1313
import './consecutive_popovers';
1414
import './popover_inside_trigger';
1515
import './cursor_tracing';
16+
import './constraint_options';

storybook/stories/styles.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@ body {
5353
}
5454

5555
.popoverjs-content {
56-
height: 100px;
56+
height: 200px;
5757
width: 100px;
5858
}

0 commit comments

Comments
 (0)