bm-core-ui 2.8.2 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/@types/index.d.ts +327 -31
- package/build/BMCollectionView/BMCollectionView.js +33 -16
- package/build/BMCollectionView/BMCollectionViewFlowLayout.js +159 -39
- package/build/BMCollectionView/BMCollectionViewLayout.js +4 -1
- package/build/BMCoreUI.css +161 -13
- package/build/BMView/BMLayoutConstraint_v2.5.js +1 -1
- package/build/BMView/BMMenu.js +790 -65
- package/build/BMView/BMScrollView.js +1 -1
- package/build/BMView/BMTextFieldDelegate.js +6 -6
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingCells.js +2 -2
- package/build/BMViewLayoutEditor/BMLayoutEditorViewSettings.js +5 -2
- package/build/BMWindow/BMConfirmationPopup.js +21 -1
- package/build/BMWindow/BMPopover/BMPopover.js +310 -52
- package/build/BMWindow/BMWindow.js +61 -18
- package/lib/@types/BMCoreUI.min.d.ts +327 -31
- package/lib/BMCoreUI.min.js +1 -1
- package/package.json +1 -1
- package/CHANGELOG.md +0 -1739
- package/build/BMViewLayoutEditor/BMLayoutEditorDelegate.js +0 -59
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingsDelegate.js +0 -46
- package/build/BMViewLayoutEditor/BMLayoutVariableProvider.js +0 -202
|
@@ -103,7 +103,7 @@ BMScrollView.prototype = BMExtend({}, BMView.prototype, {
|
|
|
103
103
|
},
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
|
-
* Invoked whenever the iScroll instance managing this scroll view's scrolling
|
|
106
|
+
* Invoked whenever the iScroll instance managing this scroll view's scrolling.
|
|
107
107
|
*/
|
|
108
108
|
_iScrollDidScroll() {
|
|
109
109
|
this._scrollOffset = BMPointMake(this._iScroll.x, this._iScroll.y);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @type interface BMTextFieldDelegate
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The specification for a `
|
|
4
|
+
* The specification for a `BMTextFieldDelegate` object, which can optionally be used in conjunction with `BMTextField` objects and will receive various
|
|
5
5
|
* callbacks related to the text field's lifecycle.
|
|
6
6
|
*/
|
|
7
7
|
function BMTextFieldDelegate() {} // <constructor>
|
|
@@ -15,7 +15,7 @@ BMTextFieldDelegate.prototype = {
|
|
|
15
15
|
*
|
|
16
16
|
* If this method is not implemented, suggestions and autocomplete will not be available.
|
|
17
17
|
* @param textField <BMTextField> The calling text field.
|
|
18
|
-
* @param text <String>
|
|
18
|
+
* @param text <String> The text for which to obtain suggestions.
|
|
19
19
|
* @return <[String]> An array of string suggestions.
|
|
20
20
|
*/
|
|
21
21
|
textFieldSuggestionsForText(textField, text) {},
|
|
@@ -47,7 +47,7 @@ BMTextFieldDelegate.prototype = {
|
|
|
47
47
|
/**
|
|
48
48
|
* Invoked whenever the contents in this text field change for any reason. This can be because of an input event,
|
|
49
49
|
* the user pasting text or a suggestion being selected.
|
|
50
|
-
* Note that this method will not be invoked when
|
|
50
|
+
* Note that this method will not be invoked when programatically setting the input node's `value`.
|
|
51
51
|
*
|
|
52
52
|
* Delegate objects can implement this method in place of standard event listeners to handle changes to this text field.
|
|
53
53
|
* The contents of the text field can be retrieved via the standard `value` property on the text field's node.
|
|
@@ -58,9 +58,9 @@ BMTextFieldDelegate.prototype = {
|
|
|
58
58
|
/**
|
|
59
59
|
* Invoked whenever the user presses the return key while the text field has keyboard focus.
|
|
60
60
|
*
|
|
61
|
-
* Delegate objects can implement this method to customize the behaviour when the user presses the return key and also control
|
|
62
|
-
* The default action for pressing the return key is to cause the text field to
|
|
63
|
-
* highlighted suggestion.
|
|
61
|
+
* Delegate objects can implement this method to customize the behaviour when the user presses the return key and also control
|
|
62
|
+
* whether the default action will take place. The default action for pressing the return key is to cause the text field to
|
|
63
|
+
* resign keyboard focus. If suggestions are used, the return key will also fill in the currently highlighted suggestion.
|
|
64
64
|
* @param textField <BMTextField> The calling text field.
|
|
65
65
|
* @return <Boolean, nullable> Defaults to `YES`. If set to `YES`, the standard behaviour will be invoked.
|
|
66
66
|
*/
|
|
@@ -518,10 +518,10 @@ BMLayoutEditorSettingsDeactivateConstraintsCell.prototype = BMExtend(Object.crea
|
|
|
518
518
|
|
|
519
519
|
buttonView.node.addEventListener('click', event => {
|
|
520
520
|
if (hasOption && hasShift && hasCtrl) {
|
|
521
|
-
new Set(this.setting.target.rootView.allConstraints).forEach(constraint => constraint.remove());
|
|
521
|
+
new Set(this.setting.target._view.rootView.allConstraints).forEach(constraint => constraint.remove());
|
|
522
522
|
}
|
|
523
523
|
else if (hasOption) {
|
|
524
|
-
for (let constraint of this.setting.target.localConstraints) {
|
|
524
|
+
for (let constraint of this.setting.target._view.localConstraints) {
|
|
525
525
|
if (hasShift) {
|
|
526
526
|
constraint.remove();
|
|
527
527
|
}
|
|
@@ -30,8 +30,11 @@ _BMLayoutEditorViewSettingsPanel.prototype = BMExtend(Object.create(_BMLayoutEdi
|
|
|
30
30
|
_layoutTab: undefined, // <BMLayoutEditorSettingsTab>
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Designated initializer. Initializes this settings panel with the
|
|
34
|
-
* @param
|
|
33
|
+
* Designated initializer. Initializes this settings panel with the specified settings view.
|
|
34
|
+
* @param settingsView <_BMLayoutSettingsView> The settings view.
|
|
35
|
+
* {
|
|
36
|
+
* @param forView <BMView> The view whose settings will be displayed.
|
|
37
|
+
* }
|
|
35
38
|
* @return <_BMLayoutEditorSettingsPanel> This setttings panel.
|
|
36
39
|
*/
|
|
37
40
|
initWithSettingsView(settingsView, {forView: view}) {
|
|
@@ -182,7 +182,12 @@ BMAlertPopup.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
182
182
|
/**
|
|
183
183
|
* The DOM node that was focused when this alert was opened.
|
|
184
184
|
*/
|
|
185
|
-
_previouslyActiveNode: undefined, // DOMNode
|
|
185
|
+
_previouslyActiveNode: undefined, // <DOMNode>
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A handler that is invoked when the window resizes, used to reposition this window.
|
|
189
|
+
*/
|
|
190
|
+
_centerHandler: undefined, // <void ^()>
|
|
186
191
|
|
|
187
192
|
/**
|
|
188
193
|
* Designated initializer. Initializes this alert popup with the given labels.
|
|
@@ -290,6 +295,15 @@ BMAlertPopup.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
290
295
|
return this._resolution;
|
|
291
296
|
},
|
|
292
297
|
|
|
298
|
+
// @override - BMWindow
|
|
299
|
+
bringToFrontAnimated() {
|
|
300
|
+
this._resizeHandler = () => this.needsLayout = YES;
|
|
301
|
+
|
|
302
|
+
window.addEventListener('resize', this._resizeHandler);
|
|
303
|
+
|
|
304
|
+
return BMWindow.prototype.bringToFrontAnimated.apply(this, arguments);
|
|
305
|
+
},
|
|
306
|
+
|
|
293
307
|
// @override - BMWindow
|
|
294
308
|
dismissAnimated() {
|
|
295
309
|
// Since the window can be dismissed by clicking outside in certain cases, this would be equivalent to pressing "OK".
|
|
@@ -302,7 +316,13 @@ BMAlertPopup.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
302
316
|
this._previouslyActiveNode.focus();
|
|
303
317
|
}
|
|
304
318
|
|
|
319
|
+
window.removeEventListener('resize', this._resizeHandler);
|
|
320
|
+
|
|
305
321
|
return BMWindow.prototype.dismissAnimated.apply(this, arguments);
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
windowDidClose() {
|
|
325
|
+
this.release();
|
|
306
326
|
}
|
|
307
327
|
|
|
308
328
|
});
|
|
@@ -8,6 +8,35 @@ import { BMHook, __BMVelocityAnimate } from "../../Core/BMAnimationContext";
|
|
|
8
8
|
import { BMView } from "../../BMView/BMView_v2.5";
|
|
9
9
|
import { BMInsetMakeWithEqualInsets } from "../../Core/BMInset";
|
|
10
10
|
|
|
11
|
+
// @type BMPopoverIndicatorDirection
|
|
12
|
+
|
|
13
|
+
// @endtype
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Constants describing the position where the indicator appears on its popover.
|
|
17
|
+
*/
|
|
18
|
+
export var BMPopoverIndicatorDirection = Object.freeze({ // <enum>
|
|
19
|
+
/**
|
|
20
|
+
* Causes the popover indicator to appear on the top edge of the popover.
|
|
21
|
+
*/
|
|
22
|
+
Top: "Top", // <enum>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Causes the popover indicator to appear on the bottom edge of the popover.
|
|
26
|
+
*/
|
|
27
|
+
Bottom: "Bottom", // <enum>
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Causes the popover indicator to appear on the left edge of the popover.
|
|
31
|
+
*/
|
|
32
|
+
Left: "Left", // <enum>
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Causes the popover indicator to appear on the right edge of the popover.
|
|
36
|
+
*/
|
|
37
|
+
Right: "Right" // <enum>
|
|
38
|
+
});
|
|
39
|
+
|
|
11
40
|
// @type BMPopover extends BMWindow
|
|
12
41
|
|
|
13
42
|
/**
|
|
@@ -90,7 +119,7 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
90
119
|
* Controls how rounded the popover's borders should be. This property should be set prior to the
|
|
91
120
|
* popover being displayed.
|
|
92
121
|
*/
|
|
93
|
-
_borderRadius:
|
|
122
|
+
_borderRadius: 8, // <Number>
|
|
94
123
|
get borderRadius() {
|
|
95
124
|
return this._borderRadius;
|
|
96
125
|
},
|
|
@@ -182,6 +211,16 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
182
211
|
*/
|
|
183
212
|
_contentViewBottomConstraint: undefined, // <BMLayoutConstraint>
|
|
184
213
|
|
|
214
|
+
/**
|
|
215
|
+
* The content view's left edge constraint.
|
|
216
|
+
*/
|
|
217
|
+
_contentViewLeftConstraint: undefined, // <BMLayoutConstraint>
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The content view's right edge constraint.
|
|
221
|
+
*/
|
|
222
|
+
_contentViewRightConstraint: undefined, // <BMLayoutConstraint>
|
|
223
|
+
|
|
185
224
|
/**
|
|
186
225
|
* The computed height of the indicator.
|
|
187
226
|
*/
|
|
@@ -190,6 +229,18 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
190
229
|
return indicatorWidth / 2 | 0;
|
|
191
230
|
},
|
|
192
231
|
|
|
232
|
+
/**
|
|
233
|
+
* An array that specifies the permitted indicator directions that this popover
|
|
234
|
+
* may use and the priority in which they will be evaluated.
|
|
235
|
+
*/
|
|
236
|
+
_permittedDirections: [BMPopoverIndicatorDirection.Bottom, BMPopoverIndicatorDirection.Top, BMPopoverIndicatorDirection.Right, BMPopoverIndicatorDirection.Left], // <[BMPopoverIndicatorDirection]>
|
|
237
|
+
get permittedDirections() {
|
|
238
|
+
return this._permittedDirections.slice();
|
|
239
|
+
},
|
|
240
|
+
set permittedDirections(directions) {
|
|
241
|
+
this._permittedDirections = directions.slice();
|
|
242
|
+
},
|
|
243
|
+
|
|
193
244
|
/**
|
|
194
245
|
* Designated initializer. Initializes this popover with the given size.
|
|
195
246
|
*
|
|
@@ -239,8 +290,12 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
239
290
|
const contentView = this._contentView = BMView.view();
|
|
240
291
|
this.addSubview(this._contentView);
|
|
241
292
|
|
|
242
|
-
contentView.
|
|
243
|
-
|
|
293
|
+
this._contentViewLeftConstraint = contentView.left.equalTo(this.left);
|
|
294
|
+
this._contentViewLeftConstraint.isActive = YES;
|
|
295
|
+
|
|
296
|
+
this._contentViewRightConstraint = contentView.right.equalTo(this.right);
|
|
297
|
+
this._contentViewRightConstraint.isActive = YES;
|
|
298
|
+
|
|
244
299
|
this._contentViewTopConstraint = contentView.top.equalTo(this.top);
|
|
245
300
|
this._contentViewTopConstraint.isActive = YES;
|
|
246
301
|
|
|
@@ -266,38 +321,108 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
266
321
|
const nodeFrame = this.anchorRect || (this.anchorNode && BMRectMakeWithNodeFrame(this.anchorNode));
|
|
267
322
|
const location = this.anchorPoint ? this.anchorPoint.copy() : nodeFrame.center;
|
|
268
323
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
324
|
+
// Determine the appropriate direction to display this popover
|
|
325
|
+
let direction;
|
|
326
|
+
if (this.anchorPoint) {
|
|
327
|
+
direction = this._directionAroundPoint(location);
|
|
273
328
|
}
|
|
274
|
-
|
|
275
|
-
|
|
329
|
+
else {
|
|
330
|
+
direction = this._directionAroundRect(nodeFrame);
|
|
276
331
|
}
|
|
277
332
|
|
|
278
|
-
|
|
333
|
+
// Adjust the constraints based on the direction
|
|
334
|
+
switch (direction) {
|
|
335
|
+
case BMPopoverIndicatorDirection.Top:
|
|
336
|
+
frame.origin.y = this.anchorPoint ? location.y : nodeFrame.bottom - 2;
|
|
279
337
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
338
|
+
frame.origin.x = location.x - frame.size.width / 2 | 0;
|
|
339
|
+
|
|
340
|
+
if (frame.origin.x < this._edgeInsets.left) {
|
|
341
|
+
frame.origin.x = this._edgeInsets.left;
|
|
342
|
+
}
|
|
343
|
+
if (frame.right > window.innerWidth - this._edgeInsets.right) {
|
|
344
|
+
frame.origin.x = window.innerWidth - frame.size.width - this._edgeInsets.right;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
this._contentViewTopConstraint.constant = this._indicatorHeight;
|
|
348
|
+
this._contentViewBottomConstraint.constant = 0;
|
|
349
|
+
this._contentViewLeftConstraint.constant = 0;
|
|
350
|
+
this._contentViewRightConstraint.constant = 0;
|
|
351
|
+
break;
|
|
352
|
+
case BMPopoverIndicatorDirection.Bottom:
|
|
353
|
+
frame.origin.y = this.anchorPoint ? location.y - frame.size.height : nodeFrame.origin.y + 2 - frame.size.height;
|
|
354
|
+
|
|
355
|
+
frame.origin.x = location.x - frame.size.width / 2 | 0;
|
|
356
|
+
|
|
357
|
+
if (frame.origin.x < this._edgeInsets.left) {
|
|
358
|
+
frame.origin.x = this._edgeInsets.left;
|
|
359
|
+
}
|
|
360
|
+
if (frame.right > window.innerWidth - this._edgeInsets.right) {
|
|
361
|
+
frame.origin.x = window.innerWidth - frame.size.width - this._edgeInsets.right;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this._contentViewTopConstraint.constant = 0;
|
|
365
|
+
this._contentViewBottomConstraint.constant = -this._indicatorHeight;
|
|
366
|
+
this._contentViewLeftConstraint.constant = 0;
|
|
367
|
+
this._contentViewRightConstraint.constant = 0;
|
|
368
|
+
break;
|
|
369
|
+
case BMPopoverIndicatorDirection.Right:
|
|
370
|
+
frame.origin.x = this.anchorPoint ? location.x - frame.size.width : nodeFrame.origin.x + 2 - frame.size.width;
|
|
371
|
+
|
|
372
|
+
frame.origin.y = location.y - frame.size.height / 2 | 0;
|
|
373
|
+
|
|
374
|
+
if (frame.origin.y < this._edgeInsets.top) {
|
|
375
|
+
frame.origin.y = this._edgeInsets.top;
|
|
376
|
+
}
|
|
377
|
+
if (frame.bottom > window.innerHeight - this._edgeInsets.bottom) {
|
|
378
|
+
frame.origin.y = window.innerHeight - frame.size.height - this._edgeInsets.bottom;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
this._contentViewTopConstraint.constant = 0;
|
|
382
|
+
this._contentViewBottomConstraint.constant = 0;
|
|
383
|
+
this._contentViewLeftConstraint.constant = 0;
|
|
384
|
+
this._contentViewRightConstraint.constant = -this._indicatorHeight;
|
|
385
|
+
break;
|
|
386
|
+
case BMPopoverIndicatorDirection.Left:
|
|
387
|
+
frame.origin.x = this.anchorPoint ? location.x : nodeFrame.right - 2;
|
|
388
|
+
|
|
389
|
+
frame.origin.y = location.y - frame.size.height / 2 | 0;
|
|
390
|
+
|
|
391
|
+
if (frame.origin.y < this._edgeInsets.top) {
|
|
392
|
+
frame.origin.y = this._edgeInsets.top;
|
|
393
|
+
}
|
|
394
|
+
if (frame.bottom > window.innerHeight - this._edgeInsets.bottom) {
|
|
395
|
+
frame.origin.y = window.innerHeight - frame.size.height - this._edgeInsets.bottom;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
this._contentViewTopConstraint.constant = 0;
|
|
399
|
+
this._contentViewBottomConstraint.constant = 0;
|
|
400
|
+
this._contentViewLeftConstraint.constant = this._indicatorHeight;
|
|
401
|
+
this._contentViewRightConstraint.constant = 0;
|
|
402
|
+
break;
|
|
289
403
|
}
|
|
290
404
|
|
|
291
405
|
this.frame = frame;
|
|
292
406
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
407
|
+
// Determine the indicator's position along its edge
|
|
408
|
+
let indicatorPosition;
|
|
409
|
+
switch (direction) {
|
|
410
|
+
case BMPopoverIndicatorDirection.Bottom:
|
|
411
|
+
case BMPopoverIndicatorDirection.Top:
|
|
412
|
+
indicatorPosition = BMNumberByConstrainingNumberToBounds(location.x - frame.origin.x, 12, frame.size.width - 12);
|
|
413
|
+
break;
|
|
414
|
+
case BMPopoverIndicatorDirection.Left:
|
|
415
|
+
case BMPopoverIndicatorDirection.Right:
|
|
416
|
+
indicatorPosition = BMNumberByConstrainingNumberToBounds(location.y - frame.origin.y, 12, frame.size.height - 12);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
296
419
|
|
|
420
|
+
// Create an inner frame to be used by the various paths
|
|
421
|
+
const innerFrame = frame.copy();
|
|
297
422
|
innerFrame.origin = BMPointMake();
|
|
298
423
|
|
|
299
|
-
const pathContent = `${this._pathForPopoverWithFrame(innerFrame, {
|
|
300
|
-
const outlinePathContent = `${this._pathForPopoverWithFrame(innerFrame, {
|
|
424
|
+
const pathContent = `${this._pathForPopoverWithFrame(innerFrame, {indicatorSize: this._indicatorSize, position: indicatorPosition, direction, radius: this._borderRadius})}`;
|
|
425
|
+
const outlinePathContent = `${this._pathForPopoverWithFrame(innerFrame, {indicatorSize: this._indicatorSize, inset: 1, position: indicatorPosition, direction, radius: this._borderRadius})}`;
|
|
301
426
|
|
|
302
427
|
if (!this._clipPathUUID && !CSS.supports('clip-path', `path('${pathContent}')`)) {
|
|
303
428
|
// If inline path definitions are not supported by the browsers, create an UUID for a SVG clip path and create it
|
|
@@ -362,64 +487,197 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
|
|
|
362
487
|
|
|
363
488
|
const popoverLayers = [this.contentNode, this._background, this._dropShadowContainer];
|
|
364
489
|
|
|
490
|
+
let transformOriginX, transformOriginY;
|
|
491
|
+
switch (direction) {
|
|
492
|
+
case BMPopoverIndicatorDirection.Bottom:
|
|
493
|
+
transformOriginX = ((indicatorPosition / this.frame.size.width) * 100) + '%';
|
|
494
|
+
transformOriginY = '100%';
|
|
495
|
+
break;
|
|
496
|
+
case BMPopoverIndicatorDirection.Top:
|
|
497
|
+
transformOriginX = ((indicatorPosition / this.frame.size.width) * 100) + '%';
|
|
498
|
+
transformOriginY = '0%';
|
|
499
|
+
break;
|
|
500
|
+
case BMPopoverIndicatorDirection.Left:
|
|
501
|
+
transformOriginX = '0%';
|
|
502
|
+
transformOriginY = ((indicatorPosition / this.frame.size.height) * 100) + '%';
|
|
503
|
+
break;
|
|
504
|
+
case BMPopoverIndicatorDirection.Right:
|
|
505
|
+
transformOriginX = '100%';
|
|
506
|
+
transformOriginY = ((indicatorPosition / this.frame.size.height) * 100) + '%';
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
|
|
365
510
|
for (const layer of popoverLayers) {
|
|
366
|
-
layer.style.transformOrigin =
|
|
511
|
+
layer.style.transformOrigin = `${transformOriginX} ${transformOriginY}`;
|
|
367
512
|
}
|
|
368
513
|
},
|
|
369
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Determines the direction that the popover should appear in order to fit best around the given point.
|
|
517
|
+
* The popover will verify directions in the order specified by the `permittedDirections` property.
|
|
518
|
+
* If none of the permitted indicator directions would fit the popover in the viewport, the first
|
|
519
|
+
* specified direction is returned.
|
|
520
|
+
* @param point <BMPoint> The anchor point to check against.
|
|
521
|
+
* @return <BMPopoverIndicatorDirection> The direction that best fits.
|
|
522
|
+
*/
|
|
523
|
+
_directionAroundPoint(point) {
|
|
524
|
+
for (const direction of this._permittedDirections) {
|
|
525
|
+
switch (direction) {
|
|
526
|
+
case BMPopoverIndicatorDirection.Top:
|
|
527
|
+
if (point.y < window.innerHeight - this.size.height - this._indicatorHeight) {
|
|
528
|
+
return BMPopoverIndicatorDirection.Top;
|
|
529
|
+
}
|
|
530
|
+
break;
|
|
531
|
+
case BMPopoverIndicatorDirection.Bottom:
|
|
532
|
+
if (point.y > this.size.height + this._indicatorHeight) {
|
|
533
|
+
return BMPopoverIndicatorDirection.Bottom;
|
|
534
|
+
}
|
|
535
|
+
break;
|
|
536
|
+
case BMPopoverIndicatorDirection.Right:
|
|
537
|
+
if (point.x > this.size.width + this._indicatorHeight) {
|
|
538
|
+
return BMPopoverIndicatorDirection.Right;
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
541
|
+
case BMPopoverIndicatorDirection.Left:
|
|
542
|
+
if (point.x < window.innerWidth - this.size.width - this._indicatorHeight) {
|
|
543
|
+
return BMPopoverIndicatorDirection.Left;
|
|
544
|
+
}
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return this._permittedDirections[0];
|
|
550
|
+
},
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Determines the direction that the popover should appear in order to fit best around the given rect.
|
|
554
|
+
* The popover will verify directions in the order specified by the `permittedDirections` property.
|
|
555
|
+
* If none of the permitted indicator directions would fit the popover in the viewport, the first
|
|
556
|
+
* specified direction is returned.
|
|
557
|
+
* @param rect <BMRect> The anchor rect to check against.
|
|
558
|
+
* @return <BMPopoverIndicatorDirection> The direction that best fits.
|
|
559
|
+
*/
|
|
560
|
+
_directionAroundRect(rect) {
|
|
561
|
+
for (const direction of this._permittedDirections) {
|
|
562
|
+
switch (direction) {
|
|
563
|
+
case BMPopoverIndicatorDirection.Top:
|
|
564
|
+
if (rect.bottom < window.innerHeight - this.size.height - this._indicatorHeight) {
|
|
565
|
+
return BMPopoverIndicatorDirection.Top;
|
|
566
|
+
}
|
|
567
|
+
break;
|
|
568
|
+
case BMPopoverIndicatorDirection.Bottom:
|
|
569
|
+
if (rect.top > this.size.height + this._indicatorHeight) {
|
|
570
|
+
return BMPopoverIndicatorDirection.Bottom;
|
|
571
|
+
}
|
|
572
|
+
break;
|
|
573
|
+
case BMPopoverIndicatorDirection.Right:
|
|
574
|
+
if (rect.left > this.size.width + this._indicatorHeight) {
|
|
575
|
+
return BMPopoverIndicatorDirection.Right;
|
|
576
|
+
}
|
|
577
|
+
break;
|
|
578
|
+
case BMPopoverIndicatorDirection.Left:
|
|
579
|
+
if (rect.right < window.innerWidth - this.size.width - this._indicatorHeight) {
|
|
580
|
+
return BMPopoverIndicatorDirection.Left;
|
|
581
|
+
}
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return this._permittedDirections[0];
|
|
587
|
+
},
|
|
588
|
+
|
|
370
589
|
/**
|
|
371
590
|
* Builds the SVG path definition for a popover with the given frame. Note that the indicator will be positioned inside the frame, which will push the usable
|
|
372
591
|
* area of the frame downwards.
|
|
373
|
-
* @param frame <BMRect>
|
|
592
|
+
* @param frame <BMRect> The popover's frame.
|
|
374
593
|
* {
|
|
375
|
-
* @param
|
|
376
|
-
* @param radius <Number, nullable>
|
|
377
|
-
* @param inset <Number, nullable>
|
|
378
|
-
* @param
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
* @param
|
|
594
|
+
* @param indicatorSize <Number, nullable> Defaults to `8`. The size of the popover's indicator.
|
|
595
|
+
* @param radius <Number, nullable> Defaults to `4`. Controls how rounded the corners are.
|
|
596
|
+
* @param inset <Number, nullable> Defaults to `0`. An optional inset to apply to the path.
|
|
597
|
+
* @param position <Number, nullable> Defaults to half of the frame's width. The position along the edge of the frame on which to place the indicator.
|
|
598
|
+
* This coordinate is relative to the popover's frame and represents the center position of the indicator.
|
|
599
|
+
* This position should not overlap the specified corner radius.
|
|
600
|
+
* @param direction <BMPopoverIndicatorDirection, nullable> Defaults to `.Top`. Controls where the indicator will be placed relative to the popover.
|
|
382
601
|
* }
|
|
383
602
|
* @return <String> The SVG path.
|
|
384
603
|
*/
|
|
385
|
-
_pathForPopoverWithFrame(frame, {
|
|
386
|
-
|
|
387
|
-
let
|
|
388
|
-
|
|
604
|
+
_pathForPopoverWithFrame(frame, {indicatorSize = 8, radius = 8, inset = 0, position = undefined, direction = BMPopoverIndicatorDirection.Top} = {indicatorSize: 8, radius: 4, inset: 0}) {
|
|
605
|
+
// Adjust the appropriate edge's position depending on the indicator direction
|
|
606
|
+
let top = direction === BMPopoverIndicatorDirection.Top ? indicatorSize * Math.SQRT2 / 2 | 0 : 0;
|
|
607
|
+
let left = direction == BMPopoverIndicatorDirection.Left ? indicatorSize * Math.SQRT2 / 2 | 0 : 0;
|
|
608
|
+
|
|
609
|
+
let bottom = direction === BMPopoverIndicatorDirection.Bottom ? frame.size.height - indicatorSize * Math.SQRT2 / 2 | 0 : frame.size.height;
|
|
610
|
+
let right = direction == BMPopoverIndicatorDirection.Right ? frame.size.width - indicatorSize * Math.SQRT2 / 2 | 0 : frame.size.width;
|
|
389
611
|
|
|
390
612
|
if (inset) {
|
|
391
|
-
|
|
613
|
+
// If an inset is specified, adjust the values appropriately
|
|
614
|
+
indicatorSize = indicatorSize - inset;
|
|
392
615
|
frame = frame.copy();
|
|
393
616
|
frame.insetWithInset(BMInsetMakeWithEqualInsets(inset));
|
|
394
617
|
radius = radius + inset;
|
|
618
|
+
|
|
395
619
|
top += inset;
|
|
620
|
+
left += inset;
|
|
621
|
+
|
|
396
622
|
bottom -= inset;
|
|
623
|
+
right -= inset;
|
|
397
624
|
}
|
|
398
625
|
|
|
399
|
-
if (
|
|
400
|
-
|
|
626
|
+
if (position === undefined) {
|
|
627
|
+
position = frame.size.width / 2 | 0;
|
|
401
628
|
}
|
|
402
629
|
else {
|
|
403
|
-
|
|
630
|
+
position = (position - inset) | 0;
|
|
404
631
|
}
|
|
405
632
|
|
|
406
|
-
const knobWidth =
|
|
633
|
+
const knobWidth = indicatorSize * Math.SQRT2;
|
|
407
634
|
const knobHeight = knobWidth / 2 | 0;
|
|
408
635
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
`M${left + radius},${top}
|
|
412
|
-
`
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
`
|
|
416
|
-
`
|
|
636
|
+
const pathTop = direction === BMPopoverIndicatorDirection.Top ?
|
|
637
|
+
// Start at top left, then draw the indicator and move to the end of the edge
|
|
638
|
+
`M${left + radius},${top} ` +
|
|
639
|
+
`L${(position - knobWidth / 2 + left)},${top} l${(knobWidth / 2)},${-knobHeight} l${(knobWidth / 2)},${knobHeight} ` +
|
|
640
|
+
`L${right - radius},${top} ` :
|
|
641
|
+
// Start at top left, then move to the end of the edge
|
|
642
|
+
`M${left + radius},${top} ` +
|
|
643
|
+
`L${right - radius},${top} `;
|
|
644
|
+
|
|
645
|
+
const pathRight = direction == BMPopoverIndicatorDirection.Right ?
|
|
646
|
+
// Draw the rounded corner, then the indicator and move to the end of the edge
|
|
647
|
+
`Q${right},${top} ${right},${top + radius} ` +
|
|
648
|
+
`L${right},${(position - knobWidth / 2 + top)} l${knobHeight},${(knobWidth / 2)} l${-knobHeight},${(knobWidth / 2)} ` +
|
|
649
|
+
`L${right},${bottom - radius} ` :
|
|
650
|
+
// Draw the rounded corner, then move to the end of the dge
|
|
651
|
+
`Q${right},${top} ${right},${top + radius} ` +
|
|
652
|
+
`L${right},${bottom - radius} `;
|
|
653
|
+
|
|
654
|
+
const pathBottom = direction === BMPopoverIndicatorDirection.Bottom ?
|
|
655
|
+
// Draw the rounded corner, then the indicator and move to the end of the edge
|
|
656
|
+
`Q${right},${bottom} ${right - radius},${bottom} ` +
|
|
657
|
+
`L${(position + knobWidth / 2 + left)},${bottom} l${(-knobWidth / 2)},${knobHeight} l${(-knobWidth / 2)},${-knobHeight} ` +
|
|
658
|
+
`L${left + radius},${bottom} ` :
|
|
659
|
+
// Draw the rounded corner, then move to the end of the edge
|
|
660
|
+
`Q${right},${bottom} ${right - radius},${bottom} ` +
|
|
661
|
+
`L${left + radius},${bottom} `;
|
|
662
|
+
|
|
663
|
+
const pathLeft = direction === BMPopoverIndicatorDirection.Left ?
|
|
664
|
+
// Draw the rounded corner coming from the bottom left, then the indicator
|
|
665
|
+
// afterwards move to the end of the edge and finally draw the rounded corner coming from the left to top
|
|
666
|
+
`Q${left},${bottom} ${left},${bottom - radius} ` +
|
|
667
|
+
`L${left},${(position + knobWidth / 2 + top)} l${-knobHeight},${(-knobWidth / 2)} l${knobHeight},${(-knobWidth / 2)} ` +
|
|
668
|
+
`L${left},${top + radius} ` +
|
|
669
|
+
`Q${left},${top} ${left + radius},${top} Z` :
|
|
670
|
+
// Draw the rounded corner coming from the bottom left, then move to
|
|
671
|
+
// the end of the edge and finally draw the rounded corner coming from the left to top
|
|
672
|
+
`Q${left},${bottom} ${left},${bottom - radius} ` +
|
|
673
|
+
`L${left},${top + radius} ` +
|
|
674
|
+
`Q${left},${top} ${left + radius},${top} Z`;
|
|
417
675
|
|
|
418
676
|
|
|
419
677
|
let path = pathTop;
|
|
420
|
-
path +=
|
|
678
|
+
path += pathRight; //`Q${right},${top} ${right},${top + radius} L${right},${bottom - radius} `;
|
|
421
679
|
path += pathBottom;
|
|
422
|
-
path +=
|
|
680
|
+
path += pathLeft; //`Q${left},${bottom} ${left},${bottom - radius} L${left},${top + radius} Q${left},${top} ${radius},${top} Z`;
|
|
423
681
|
|
|
424
682
|
return path;
|
|
425
683
|
},
|