@brightspace-ui/core 3.88.4 → 3.89.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.
@@ -63,7 +63,7 @@ export const PopoverMixin = superclass => class extends superclass {
63
63
  --d2l-popover-default-border-color: var(--d2l-color-mica);
64
64
  --d2l-popover-default-border-radius: 0.3rem;
65
65
  --d2l-popover-default-foreground-color: var(--d2l-color-ferrite);
66
- --d2l-popover-default-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.15);
66
+ --d2l-popover-default-shadow-color: rgba(0, 0, 0, 0.15);
67
67
  background-color: transparent; /* override popover default */
68
68
  border: none; /* override popover */
69
69
  box-sizing: border-box;
@@ -75,8 +75,17 @@ export const PopoverMixin = superclass => class extends superclass {
75
75
  overflow: visible; /* override popover */
76
76
  padding: 0; /* override popover */
77
77
  position: fixed; /* normalize popover */
78
+ text-align: start;
78
79
  width: fit-content; /* normalize popover */
79
80
  }
81
+ :host([theme="dark"]) {
82
+ --d2l-popover-default-animation-name: d2l-popover-animation-dark;
83
+ --d2l-popover-default-background-color: #333536; /* tungsten @ 70% */
84
+ --d2l-popover-default-border-color: var(--d2l-color-tungsten);
85
+ --d2l-popover-default-foreground-color: var(--d2l-color-sylvite);
86
+ --d2l-popover-default-shadow-color: rgba(0, 0, 0, 1);
87
+ opacity: 0.9;
88
+ }
80
89
  :host([hidden]) {
81
90
  display: none;
82
91
  }
@@ -99,8 +108,9 @@ export const PopoverMixin = superclass => class extends superclass {
99
108
  background-color: var(--d2l-popover-background-color, var(--d2l-popover-default-background-color));
100
109
  border: 1px solid var(--d2l-popover-border-color, var(--d2l-popover-default-border-color));
101
110
  border-radius: var(--d2l-popover-border-radius, var(--d2l-popover-default-border-radius));
102
- box-shadow: var(--d2l-popover-shadow, var(--d2l-popover-default-shadow));
111
+ box-shadow: 0 2px 12px 0 var(--d2l-popover-shadow-color, var(--d2l-popover-default-shadow-color));
103
112
  box-sizing: border-box;
113
+ display: flex;
104
114
  max-width: 370px;
105
115
  min-width: 70px;
106
116
  width: 100vw;
@@ -109,6 +119,7 @@ export const PopoverMixin = superclass => class extends superclass {
109
119
  box-sizing: border-box;
110
120
  display: inline-block;
111
121
  max-width: 100%;
122
+ min-width: inherit;
112
123
  outline: none;
113
124
  overflow-y: auto;
114
125
  }
@@ -142,6 +153,10 @@ export const PopoverMixin = superclass => class extends superclass {
142
153
  0% { opacity: 0; transform: translate(0, -10px); }
143
154
  100% { opacity: 1; transform: translate(0, 0); }
144
155
  }
156
+ @keyframes d2l-popover-animation-dark {
157
+ 0% { opacity: 0; transform: translate(0, -10px); }
158
+ 100% { opacity: 0.9; transform: translate(0, 0); }
159
+ }
145
160
  @media (prefers-reduced-motion: no-preference) {
146
161
  :host([_opened]) {
147
162
  animation: var(--d2l-popover-animation-name, var(--d2l-popover-default-animation-name)) 300ms ease;
@@ -259,6 +274,8 @@ export const PopoverMixin = superclass => class extends superclass {
259
274
 
260
275
  await this.updateComplete; // wait before applying focus to opener
261
276
  this.#focusOpener();
277
+
278
+ /** @ignore */
262
279
  this.dispatchEvent(new CustomEvent('d2l-popover-close', { bubbles: true, composed: true }));
263
280
 
264
281
  }
@@ -290,7 +307,7 @@ export const PopoverMixin = superclass => class extends superclass {
290
307
  this._trapFocus = properties?.trapFocus ?? false;
291
308
  }
292
309
 
293
- async open(applyFocus = true) {
310
+ async open(opener, applyFocus = true) {
294
311
  if (this._opened) return;
295
312
 
296
313
  const ifrauBackdropService = await tryGetIfrauBackdropService();
@@ -306,10 +323,10 @@ export const PopoverMixin = superclass => class extends superclass {
306
323
 
307
324
  this._previousFocusableAncestor = getPreviousFocusableAncestor(this, false, false);
308
325
 
309
- this._opener = getComposedActiveElement();
326
+ this._opener = opener;
310
327
  this.#addAutoCloseHandlers();
311
328
 
312
- await this.#position();
329
+ await this.position();
313
330
 
314
331
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
315
332
  if (ifrauBackdropService && this._showBackdrop) {
@@ -322,10 +339,99 @@ export const PopoverMixin = superclass => class extends superclass {
322
339
 
323
340
  this.#addRepositionHandlers();
324
341
 
342
+ /** @ignore */
325
343
  this.dispatchEvent(new CustomEvent('d2l-popover-open', { bubbles: true, composed: true }));
326
344
 
327
345
  }
328
346
 
347
+ async position(contentRect, options) {
348
+ if (!this._opener) return;
349
+
350
+ options = Object.assign({ updateLocation: true, updateHeight: true }, options);
351
+
352
+ const content = this.#getContentContainer();
353
+
354
+ if (!this._noAutoFit && options.updateHeight) {
355
+ this._contentHeight = null;
356
+ }
357
+
358
+ // don't let popover content horizontally overflow viewport
359
+ this._width = null;
360
+
361
+ await this.updateComplete;
362
+
363
+ const adjustPosition = async() => {
364
+
365
+ const scrollHeight = document.documentElement.scrollHeight;
366
+ const openerRect = this._opener.getBoundingClientRect();
367
+ contentRect = contentRect ?? content.getBoundingClientRect();
368
+
369
+ const height = this._minHeight ?? Math.min(this._maxHeight ?? Number.MAX_VALUE, contentRect.height);
370
+
371
+ const spaceRequired = {
372
+ height: height + 10,
373
+ width: contentRect.width
374
+ };
375
+
376
+ // space in viewport
377
+ const spaceAround = this.#constrainSpaceAround({
378
+ // allow for opener offset + outer margin
379
+ above: openerRect.top - this._offset - this._margin,
380
+ // allow for opener offset + outer margin
381
+ below: window.innerHeight - openerRect.bottom - this._offset - this._margin,
382
+ // allow for outer margin
383
+ left: openerRect.left - 20,
384
+ // allow for outer margin
385
+ right: document.documentElement.clientWidth - openerRect.right - 15
386
+ }, spaceRequired, openerRect);
387
+
388
+ // space in document
389
+ const spaceAroundScroll = this.#constrainSpaceAround({
390
+ above: openerRect.top + document.documentElement.scrollTop,
391
+ below: scrollHeight - openerRect.bottom - document.documentElement.scrollTop
392
+ }, spaceRequired, openerRect);
393
+
394
+ if (options.updateLocation) {
395
+ this._location = this.#getLocation(spaceAround, spaceAroundScroll, spaceRequired);
396
+ }
397
+
398
+ this._position = this.#getPosition(spaceAround, openerRect, contentRect);
399
+ if (!this._noPointer) this._pointerPosition = this.#getPointerPosition(openerRect);
400
+
401
+ if (options.updateHeight) {
402
+
403
+ // calculate height available to the popover contents for overflow because that is the only area capable of scrolling
404
+ const availableHeight = (this._location === 'block-start') ? spaceAround.above : spaceAround.below;
405
+
406
+ if (!this._noAutoFit && availableHeight && availableHeight > 0) {
407
+ // only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
408
+ this._contentHeight = this._maxHeight !== null && availableHeight > this._maxHeight
409
+ ? this._maxHeight - 2 : availableHeight;
410
+
411
+ // ensure the content height has updated when the __toggleScrollStyles event handler runs
412
+ await this.updateComplete;
413
+ }
414
+
415
+ // todo: handle inline-start and inline-end locations
416
+
417
+ }
418
+
419
+ /** @ignore */
420
+ this.dispatchEvent(new CustomEvent('d2l-popover-position', { bubbles: true, composed: true }));
421
+
422
+ };
423
+
424
+ const scrollWidth = content.scrollWidth;
425
+ const availableWidth = window.innerWidth - 40;
426
+
427
+ this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth);
428
+
429
+ await this.updateComplete;
430
+
431
+ await adjustPosition();
432
+
433
+ }
434
+
329
435
  renderPopover(content) {
330
436
 
331
437
  const mobileTrayLocation = this._mobile ? this._mobileTrayLocation : null;
@@ -392,12 +498,12 @@ export const PopoverMixin = superclass => class extends superclass {
392
498
  async resize() {
393
499
  if (!this._opened) return;
394
500
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
395
- await this.#position();
501
+ await this.position();
396
502
  }
397
503
 
398
- toggleOpen(applyFocus = true) {
504
+ toggleOpen(opener, applyFocus = true) {
399
505
  if (this._opened) return this.close();
400
- else return this.open(!this._noAutoFocus && applyFocus);
506
+ else return this.open(opener, (!this._noAutoFocus && applyFocus));
401
507
  }
402
508
 
403
509
  #ifrauContextInfo;
@@ -864,7 +970,7 @@ export const PopoverMixin = superclass => class extends superclass {
864
970
  #handleFocusTrapEnter() {
865
971
  this.#focusContent(this.#getContentContainer());
866
972
 
867
- /** Dispatched when user focus enters the popover (trap-focus option only) */
973
+ /** @ignore */
868
974
  this.dispatchEvent(new CustomEvent('d2l-popover-focus-enter', { detail: { applyFocus: this._applyFocus } }));
869
975
  }
870
976
 
@@ -872,7 +978,7 @@ export const PopoverMixin = superclass => class extends superclass {
872
978
  this._mobile = this.#mediaQueryList.matches;
873
979
  if (this._opened) {
874
980
  this._showBackdrop = this._mobile && this._mobileTrayLocation;
875
- await this.#position();
981
+ await this.position();
876
982
  }
877
983
  }
878
984
 
@@ -880,94 +986,6 @@ export const PopoverMixin = superclass => class extends superclass {
880
986
  this.resize();
881
987
  }
882
988
 
883
- async #position(contentRect, options) {
884
- if (!this._opener) return;
885
-
886
- options = Object.assign({ updateLocation: true, updateHeight: true }, options);
887
-
888
- const content = this.#getContentContainer();
889
-
890
- if (!this._noAutoFit && options.updateHeight) {
891
- this._contentHeight = null;
892
- }
893
-
894
- // don't let popover content horizontally overflow viewport
895
- this._width = null;
896
-
897
- await this.updateComplete;
898
-
899
- const adjustPosition = async() => {
900
-
901
- const scrollHeight = document.documentElement.scrollHeight;
902
- const openerRect = this._opener.getBoundingClientRect();
903
- contentRect = contentRect ?? content.getBoundingClientRect();
904
-
905
- const height = this._minHeight ?? Math.min(this._maxHeight ?? Number.MAX_VALUE, contentRect.height);
906
-
907
- const spaceRequired = {
908
- height: height + 10,
909
- width: contentRect.width
910
- };
911
-
912
- // space in viewport
913
- const spaceAround = this.#constrainSpaceAround({
914
- // allow for opener offset + outer margin
915
- above: openerRect.top - this._offset - this._margin,
916
- // allow for opener offset + outer margin
917
- below: window.innerHeight - openerRect.bottom - this._offset - this._margin,
918
- // allow for outer margin
919
- left: openerRect.left - 20,
920
- // allow for outer margin
921
- right: document.documentElement.clientWidth - openerRect.right - 15
922
- }, spaceRequired, openerRect);
923
-
924
- // space in document
925
- const spaceAroundScroll = this.#constrainSpaceAround({
926
- above: openerRect.top + document.documentElement.scrollTop,
927
- below: scrollHeight - openerRect.bottom - document.documentElement.scrollTop
928
- }, spaceRequired, openerRect);
929
-
930
- if (options.updateLocation) {
931
- this._location = this.#getLocation(spaceAround, spaceAroundScroll, spaceRequired);
932
- }
933
-
934
- this._position = this.#getPosition(spaceAround, openerRect, contentRect);
935
- if (!this._noPointer) this._pointerPosition = this.#getPointerPosition(openerRect);
936
-
937
- if (options.updateHeight) {
938
-
939
- // calculate height available to the popover contents for overflow because that is the only area capable of scrolling
940
- const availableHeight = (this._location === 'block-start') ? spaceAround.above : spaceAround.below;
941
-
942
- if (!this._noAutoFit && availableHeight && availableHeight > 0) {
943
- // only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
944
- this._contentHeight = this._maxHeight !== null && availableHeight > this._maxHeight
945
- ? this._maxHeight - 2 : availableHeight;
946
-
947
- // ensure the content height has updated when the __toggleScrollStyles event handler runs
948
- await this.updateComplete;
949
- }
950
-
951
- // todo: handle inline-start and inline-end locations
952
-
953
- }
954
-
955
- /** Dispatched when the popover position finishes adjusting */
956
- this.dispatchEvent(new CustomEvent('d2l-popover-position', { bubbles: true, composed: true }));
957
-
958
- };
959
-
960
- const scrollWidth = content.scrollWidth;
961
- const availableWidth = window.innerWidth - 40;
962
-
963
- this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth);
964
-
965
- await this.updateComplete;
966
-
967
- await adjustPosition();
968
-
969
- }
970
-
971
989
  #removeAutoCloseHandlers() {
972
990
  this.removeEventListener('blur', this.#handleAutoCloseFocusBound, { capture: true });
973
991
  document.body?.removeEventListener('focus', this.#handleAutoCloseFocusBound, { capture: true }); // DE41322: document.body can be null in some scenarios
@@ -979,7 +997,9 @@ export const PopoverMixin = superclass => class extends superclass {
979
997
  }
980
998
 
981
999
  #removeRepositionHandlers() {
982
- this._openerIntersectionObserver?.unobserve(this._opener);
1000
+ if (this._opener) {
1001
+ this._openerIntersectionObserver?.unobserve(this._opener);
1002
+ }
983
1003
  this._scrollablesObserved?.forEach(node => {
984
1004
  node.removeEventListener('scroll', this.#repositionBound);
985
1005
  });
@@ -992,7 +1012,7 @@ export const PopoverMixin = superclass => class extends superclass {
992
1012
  // throttle repositioning (https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event#scroll_event_throttling)
993
1013
  if (!this._repositioning) {
994
1014
  requestAnimationFrame(() => {
995
- this.#position(undefined, { updateLocation: false, updateHeight: false });
1015
+ this.position(undefined, { updateLocation: false, updateHeight: false });
996
1016
  this._repositioning = false;
997
1017
  });
998
1018
  }
@@ -2554,7 +2554,7 @@
2554
2554
  {
2555
2555
  "name": "d2l-dropdown-content",
2556
2556
  "path": "./components/dropdown/dropdown-content.js",
2557
- "description": "A generic container for dropdown content. It provides behavior such as sizing, positioning, and managing focus gain/loss.",
2557
+ "description": "A generic container for dropdown content. It provides behavior such as sizing, positioning, and managing focus gain/loss.",
2558
2558
  "attributes": [
2559
2559
  {
2560
2560
  "name": "align",
@@ -2599,7 +2599,8 @@
2599
2599
  {
2600
2600
  "name": "opened",
2601
2601
  "description": "Whether the dropdown is open or not",
2602
- "type": "boolean"
2602
+ "type": "boolean",
2603
+ "default": "false"
2603
2604
  },
2604
2605
  {
2605
2606
  "name": "no-auto-close",
@@ -2715,7 +2716,8 @@
2715
2716
  "name": "opened",
2716
2717
  "attribute": "opened",
2717
2718
  "description": "Whether the dropdown is open or not",
2718
- "type": "boolean"
2719
+ "type": "boolean",
2720
+ "default": "false"
2719
2721
  },
2720
2722
  {
2721
2723
  "name": "noAutoClose",
@@ -2973,7 +2975,8 @@
2973
2975
  {
2974
2976
  "name": "opened",
2975
2977
  "description": "Whether the dropdown is open or not",
2976
- "type": "boolean"
2978
+ "type": "boolean",
2979
+ "default": "false"
2977
2980
  },
2978
2981
  {
2979
2982
  "name": "no-auto-close",
@@ -3089,7 +3092,8 @@
3089
3092
  "name": "opened",
3090
3093
  "attribute": "opened",
3091
3094
  "description": "Whether the dropdown is open or not",
3092
- "type": "boolean"
3095
+ "type": "boolean",
3096
+ "default": "false"
3093
3097
  },
3094
3098
  {
3095
3099
  "name": "noAutoClose",
@@ -3347,7 +3351,8 @@
3347
3351
  {
3348
3352
  "name": "opened",
3349
3353
  "description": "Whether the dropdown is open or not",
3350
- "type": "boolean"
3354
+ "type": "boolean",
3355
+ "default": "false"
3351
3356
  },
3352
3357
  {
3353
3358
  "name": "no-auto-close",
@@ -3463,7 +3468,8 @@
3463
3468
  "name": "opened",
3464
3469
  "attribute": "opened",
3465
3470
  "description": "Whether the dropdown is open or not",
3466
- "type": "boolean"
3471
+ "type": "boolean",
3472
+ "default": "false"
3467
3473
  },
3468
3474
  {
3469
3475
  "name": "noAutoClose",
@@ -10681,12 +10687,6 @@
10681
10687
  "type": "boolean",
10682
10688
  "default": "false"
10683
10689
  },
10684
- {
10685
- "name": "opened",
10686
- "description": "Whether the popover is open or not",
10687
- "type": "boolean",
10688
- "default": "false"
10689
- },
10690
10690
  {
10691
10691
  "name": "trap-focus",
10692
10692
  "description": "Whether to render a d2l-focus-trap around the content",
@@ -10737,6 +10737,10 @@
10737
10737
  "description": "Position the popover to span from the opener edge to this grid line. Default is \"all\" (centered).",
10738
10738
  "type": "'start'|'end'|'all'"
10739
10739
  },
10740
+ {
10741
+ "name": "opened",
10742
+ "type": "boolean | undefined"
10743
+ },
10740
10744
  {
10741
10745
  "name": "noAutoClose",
10742
10746
  "attribute": "no-auto-close",
@@ -10758,13 +10762,6 @@
10758
10762
  "type": "boolean",
10759
10763
  "default": "false"
10760
10764
  },
10761
- {
10762
- "name": "opened",
10763
- "attribute": "opened",
10764
- "description": "Whether the popover is open or not",
10765
- "type": "boolean",
10766
- "default": "false"
10767
- },
10768
10765
  {
10769
10766
  "name": "trapFocus",
10770
10767
  "attribute": "trap-focus",
@@ -10772,22 +10769,6 @@
10772
10769
  "type": "boolean",
10773
10770
  "default": "false"
10774
10771
  }
10775
- ],
10776
- "events": [
10777
- {
10778
- "name": "d2l-popover-close"
10779
- },
10780
- {
10781
- "name": "d2l-popover-open"
10782
- },
10783
- {
10784
- "name": "d2l-popover-focus-enter",
10785
- "description": "Dispatched when user focus enters the popover (trap-focus option only)"
10786
- },
10787
- {
10788
- "name": "d2l-popover-position",
10789
- "description": "Dispatched when the popover position finishes adjusting"
10790
- }
10791
10772
  ]
10792
10773
  },
10793
10774
  {
@@ -0,0 +1 @@
1
+ export const getFlag = (key, defaultValue) => window.D2L?.LP?.Web?.UI?.Flags.Flag(key, defaultValue) ?? defaultValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.88.4",
3
+ "version": "3.89.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",