@brightspace-ui/core 3.173.0 → 3.174.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.
@@ -0,0 +1,10 @@
1
+ import { mockFlag } from '../../helpers/flags.js';
2
+
3
+ const urlParams = new URLSearchParams(window.location.search);
4
+
5
+ urlParams.forEach((value, key) => {
6
+ if (!key.startsWith('demo-flag-')) return;
7
+ key = key.substring(10);
8
+ if (value?.toLowerCase?.() === 'true') mockFlag(key, true);
9
+ else if (value?.toLowerCase?.() === 'false') mockFlag(key, false);
10
+ });
@@ -1,11 +1,17 @@
1
+ import './demo-flags.js';
2
+ import '../button/button.js';
1
3
  import './demo-snippet.js';
4
+ import '../inputs/input-checkbox-group.js';
5
+ import '../inputs/input-checkbox.js';
2
6
  import './code-view.js';
7
+ import '../collapsible-panel/collapsible-panel.js';
8
+ import '../collapsible-panel/collapsible-panel-summary-item.js';
3
9
  import '../colors/colors.js';
4
10
  import '../typography/typography.js';
5
11
  import { css, html, LitElement } from 'lit';
6
12
  import { getDocumentLocaleSettings, supportedLocalesDetails } from '@brightspace-ui/intl/lib/common.js';
13
+ import { getFlagOverrides, getKnownFlags } from '../../helpers/flags.js';
7
14
  import { classMap } from 'lit/directives/class-map.js';
8
- import { heading2Styles } from '../typography/styles.js';
9
15
  import { inputLabelStyles } from '../inputs/input-label-styles.js';
10
16
  import { selectStyles } from '../inputs/input-select-styles.js';
11
17
 
@@ -32,7 +38,7 @@ class DemoPage extends LitElement {
32
38
  }
33
39
 
34
40
  static get styles() {
35
- return [ heading2Styles, inputLabelStyles, selectStyles, css`
41
+ return [ inputLabelStyles, selectStyles, css`
36
42
  :host {
37
43
  background-color: var(--d2l-color-sylvite);
38
44
  display: block;
@@ -49,9 +55,8 @@ class DemoPage extends LitElement {
49
55
  margin-bottom: 1.5rem;
50
56
  max-width: 900px;
51
57
  }
52
- .d2l-heading-2 {
53
- flex-grow: 1;
54
- margin: 0;
58
+ d2l-collapsible-panel {
59
+ width: 100%;
55
60
  }
56
61
  .d2l-input-label {
57
62
  margin-bottom: 0;
@@ -68,20 +73,36 @@ class DemoPage extends LitElement {
68
73
  .d2l-demo-page-content > ::slotted(d2l-demo-snippet) {
69
74
  margin-bottom: 36px;
70
75
  }
76
+
77
+ #applyFlagsButton {
78
+ margin-block-start: 1rem;
79
+ }
71
80
  `];
72
81
  }
73
82
 
83
+ constructor() {
84
+ super();
85
+ this.#handleFlagsKnownBound = this.#handleFlagsKnown.bind(this);
86
+ }
87
+
74
88
  connectedCallback() {
75
89
  super.connectedCallback();
76
90
  const title = document.createElement('title');
77
91
  title.textContent = this.pageTitle;
78
92
  document.head.insertBefore(title, document.head.firstChild);
93
+ document.addEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
94
+ }
95
+
96
+ disconnectedCallback() {
97
+ super.disconnectedCallback();
98
+ document.removeEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
79
99
  }
80
100
 
81
101
  render() {
82
102
  const classes = {
83
103
  'no-scroll': this._noScroll
84
104
  };
105
+
85
106
  let selectedLanguageCode = getDocumentLocaleSettings().language;
86
107
  if (selectedLanguageCode === 'en') selectedLanguageCode = 'en-us';
87
108
  let foundSelected = false;
@@ -90,21 +111,79 @@ class DemoPage extends LitElement {
90
111
  foundSelected = foundSelected || selected;
91
112
  return html`<option value="${l.code}" ?selected="${selected}">${l.code} - ${l.name}</option>`;
92
113
  });
114
+
115
+ const knownFlags = this.#getKnownFlagsSorted();
116
+ const knownFlagCheckboxes = [];
117
+ knownFlags.forEach((knownFlag, key) => {
118
+ knownFlagCheckboxes.push(html`<d2l-input-checkbox label="${key}" data-flag-key="${key}" ?checked="${knownFlag.value}"></d2l-input-checkbox>`);
119
+ });
120
+
121
+ const flagOverrides = getFlagOverrides();
122
+ const flagOverrideItems = [];
123
+ flagOverrides.forEach((value, key) => {
124
+ const knownFlag = knownFlags.get(key);
125
+ const defaultValue = knownFlag ? knownFlag.defaultValue : 'unknown';
126
+ flagOverrideItems.push(html`<d2l-collapsible-panel-summary-item slot="summary" text="${key} (default: ${defaultValue}; override: ${value})"></d2l-collapsible-panel-summary-item>`);
127
+ });
128
+
93
129
  return html`
94
130
  <header>
95
- <h1 class="d2l-heading-2">${this.pageTitle}</h1>
96
- <label class="d2l-input-label">
97
- Language:
98
- <select class="d2l-input-select" @change="${this._handleLanguageChange}">${languageOptions}</select>
99
- </label>
131
+ <d2l-collapsible-panel panel-title="${this.pageTitle}" heading-level="1" heading-style="3" type="subtle">
132
+ <label class="d2l-input-label" slot="actions">
133
+ Language:
134
+ <select class="d2l-input-select" @change="${this.#handleLanguageChange}">${languageOptions}</select>
135
+ </label>
136
+ ${knownFlagCheckboxes.length > 0 ? html`
137
+ <d2l-input-checkbox-group id="flagsCheckboxGroup" label="Flags">
138
+ ${knownFlagCheckboxes}
139
+ </d2l-input-checkbox-group>
140
+ <d2l-button id="applyFlagsButton" @click="${this.#handleApplyFlagsClick}">Apply</d2l-button>
141
+ ` : 'No known flags'}
142
+ ${flagOverrideItems}
143
+ </d2l-collapsible-panel>
100
144
  </header>
101
145
  <main class="${classMap(classes)}">
102
- <div class="d2l-demo-page-content" @d2l-demo-snippet-fullscreen-toggle="${this._handleFullscreenToggle}"><slot></slot></div>
146
+ <div class="d2l-demo-page-content" @d2l-demo-snippet-fullscreen-toggle="${this.#handleFullscreenToggle}"><slot></slot></div>
103
147
  </main>
104
148
  `;
105
149
  }
106
150
 
107
- async _handleFullscreenToggle() {
151
+ #handleFlagsKnownBound;
152
+
153
+ #getKnownFlagsSorted() {
154
+ return new Map([...getKnownFlags().entries()].sort((entry1, entry2) => {
155
+ const key1 = entry1[0].toLowerCase();
156
+ const key2 = entry2[0].toLowerCase();
157
+ if (key1 < key2) return -1;
158
+ else if (key1 > key2) return 1;
159
+ else return 0;
160
+ }));
161
+ }
162
+
163
+ #handleApplyFlagsClick() {
164
+ const urlParams = new URLSearchParams(window.location.search);
165
+ const elems = [...this.shadowRoot.querySelectorAll('#flagsCheckboxGroup > d2l-input-checkbox')];
166
+
167
+ const knownFlags = getKnownFlags();
168
+ elems.forEach(elem => {
169
+ const key = elem.dataset.flagKey;
170
+ const flag = knownFlags.get(key);
171
+
172
+ if (flag.defaultValue === elem.checked) {
173
+ urlParams.delete(`demo-flag-${key}`);
174
+ } else if (flag.defaultValue !== elem.checked) {
175
+ urlParams.set(`demo-flag-${key}`, elem.checked);
176
+ }
177
+ });
178
+
179
+ window.location.search = urlParams.toString();
180
+ }
181
+
182
+ #handleFlagsKnown() {
183
+ this.requestUpdate();
184
+ }
185
+
186
+ async #handleFullscreenToggle() {
108
187
  if (this._noScroll) {
109
188
  this._noScroll = false;
110
189
  await this.updateComplete;
@@ -116,7 +195,7 @@ class DemoPage extends LitElement {
116
195
  }
117
196
  }
118
197
 
119
- _handleLanguageChange(e) {
198
+ #handleLanguageChange(e) {
120
199
  const newLanguageCode = e.target[e.target.selectedIndex].value;
121
200
  document.documentElement.dir = newLanguageCode === 'ar-sa' ? 'rtl' : 'ltr';
122
201
  document.documentElement.lang = newLanguageCode;
@@ -5,13 +5,6 @@
5
5
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
6
6
  <meta charset="UTF-8">
7
7
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
8
- <script>
9
- const urlParams = new URLSearchParams(window.location.search);
10
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
11
- if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
12
- return false;
13
- } } } } } };
14
- </script>
15
8
  <script type="module">
16
9
  import '../../demo/demo-page.js';
17
10
  import '../../menu/menu.js';
@@ -5,13 +5,6 @@
5
5
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
6
6
  <meta charset="UTF-8">
7
7
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
8
- <script>
9
- const urlParams = new URLSearchParams(window.location.search);
10
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
11
- if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
12
- return false;
13
- } } } } } };
14
- </script>
15
8
  <script type="module">
16
9
  import '../../demo/demo-page.js';
17
10
  import '../../tabs/tabs.js';
@@ -4,13 +4,6 @@
4
4
  <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
5
5
  <meta charset="UTF-8">
6
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
- <script>
8
- const urlParams = new URLSearchParams(window.location.search);
9
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
10
- if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
11
- return false;
12
- } } } } } };
13
- </script>
14
7
  <script type="module">
15
8
  import '../../demo/demo-page.js';
16
9
  import '../../button/button.js';
@@ -82,6 +82,10 @@ class EmptyStateIllustrated extends LoadingCompleteMixin(EmptyStateMixin(LitElem
82
82
  _onResize(entries) {
83
83
  if (!entries || entries.length === 0) return;
84
84
  const entry = entries[0];
85
+
86
+ const width = entry.contentRect.width;
87
+ if (width === 0) return; // ignore until visible
88
+
85
89
  requestAnimationFrame(() => {
86
90
  this._contentHeight = Math.min(entry.contentRect.right / illustrationAspectRatio, 330);
87
91
  this._titleSmall = entry.contentRect.right <= 615;
@@ -3,13 +3,6 @@
3
3
 
4
4
  <head>
5
5
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
6
- <script>
7
- const urlParams = new URLSearchParams(window.location.search);
8
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
9
- if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
10
- return false;
11
- } } } } } };
12
- </script>
13
6
  <script type="module">
14
7
  import '../../demo/demo-page.js';
15
8
  import '../../button/button.js';
@@ -4,13 +4,6 @@
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="UTF-8">
6
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
- <script>
8
- const urlParams = new URLSearchParams(window.location.search);
9
- window.D2L = { LP: { Web: { UI: { Flags: { Flag: (key) => {
10
- if (key === 'GAUD-7472-dropdown-popover') return (urlParams.get('popover') === 'true');
11
- return false;
12
- } } } } } };
13
- </script>
14
7
  <script type="module">
15
8
  import '../../demo/demo-page.js';
16
9
  import '../input-date.js';
@@ -4,12 +4,6 @@
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="UTF-8">
6
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
- <script type="module">
8
- import { mockFlag } from '../../../helpers/flags.js';
9
- const urlParams = new URLSearchParams(window.location.search);
10
- mockFlag('GAUD-8295-menu-item-link-new-window-icon', urlParams.get('link-new-window-icon') === 'true');
11
- mockFlag('GAUD-8369-menu-item-link-click-changes', urlParams.get('link-click-changes') === 'true');
12
- </script>
13
7
  <script type="module">
14
8
  import '../../demo/demo-page.js';
15
9
  import './custom-menu-item.js';
@@ -4,11 +4,6 @@
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="UTF-8">
6
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
- <script type="module">
8
- import { mockFlag } from '../../../helpers/flags.js';
9
- const urlParams = new URLSearchParams(window.location.search);
10
- mockFlag('GAUD-8263-scroll-wrapper-media-print', urlParams.get('media-query-print') === 'true');
11
- </script>
12
7
  <script type="module">
13
8
  import '../../demo/demo-page.js';
14
9
  import './scroll-wrapper-test.js';
@@ -4,11 +4,6 @@
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="UTF-8">
6
6
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
- <script type="module">
8
- import { mockFlag } from '../../../helpers/flags.js';
9
- const urlParams = new URLSearchParams(window.location.search);
10
- mockFlag('GAUD-8263-scroll-wrapper-media-print', urlParams.get('media-query-print') === 'true');
11
- </script>
12
7
  <script type="module">
13
8
  import '../../demo/demo-page.js';
14
9
  import './table-test.js';
@@ -10,6 +10,7 @@
10
10
  import '../../count-badge/count-badge.js';
11
11
  import '../../dropdown/dropdown-button-subtle.js';
12
12
  import '../../dropdown/dropdown-menu.js';
13
+ import '../../empty-state/empty-state-illustrated.js';
13
14
  import '../../menu/menu.js';
14
15
  import '../../menu/menu-item.js';
15
16
  import '../tab.js';
@@ -389,6 +390,23 @@
389
390
  </template>
390
391
  </d2l-demo-snippet>
391
392
 
393
+ <h2>Tabs (simple empty illustrated)</h2>
394
+
395
+ <d2l-demo-snippet>
396
+ <template>
397
+ <d2l-tabs text="Simple Empty States">
398
+ <d2l-tab id="simple-empty-one" slot="tabs" text="One"></d2l-tab>
399
+ <d2l-tab id="simple-empty-two" slot="tabs" text="Two"></d2l-tab>
400
+ <d2l-tab-panel labelled-by="simple-empty-one" slot="panels">
401
+ <d2l-empty-state-illustrated illustration-name="race" title-text="No Items in First Tab" description="none"></d2l-empty-state-illustrated>
402
+ </d2l-tab-panel>
403
+ <d2l-tab-panel labelled-by="simple-empty-two" slot="panels">
404
+ <d2l-empty-state-illustrated illustration-name="calendar" title-text="No Items in Second Tab" description="none"></d2l-empty-state-illustrated>
405
+ </d2l-tab-panel>
406
+ </d2l-tabs>
407
+ </template>
408
+ </d2l-demo-snippet>
409
+
392
410
  <h2>Tabs (deprecated structure)</h2>
393
411
 
394
412
  <d2l-demo-snippet>
@@ -6,14 +6,9 @@
6
6
  <meta charset="UTF-8">
7
7
  <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
8
8
  <script type="module">
9
- import { mockFlag } from '../../../helpers/flags.js';
10
- const urlParams = new URLSearchParams(window.location.search);
11
- mockFlag('GAUD-7355-tooltip-popover', urlParams.get('popover') === 'true');
12
- </script>
13
- <script type="module">
9
+ import '../../demo/demo-page.js';
14
10
  import '../../button/button.js';
15
11
  import '../../colors/colors.js';
16
- import '../../demo/demo-page.js';
17
12
  import '../../icons/icon-custom.js';
18
13
  import '../../inputs/input-text.js';
19
14
  import '../../link/link.js';
package/helpers/README.md CHANGED
@@ -117,6 +117,23 @@ getFirstVisibleAncestor(node)
117
117
  querySelectorComposed(node, selector)
118
118
  ```
119
119
 
120
+ ## Flags
121
+
122
+ Helper functions to get and mock flag values.
123
+
124
+ ```js
125
+ import { ... } from '@brightspace-ui/core/helpers/flags.js';
126
+
127
+ // returns the flag's mocked, configured, or default value
128
+ getFlag(key, defaultValue);
129
+
130
+ // for demos & tests, sets a mocked value for a flag, to be returned by getFlag
131
+ mockFlag(key, value);
132
+
133
+ // for demos & tests, removes the mocked value for a flag, so that getFlag returns the configured or default value
134
+ resetFlag(key);
135
+ ```
136
+
120
137
  ## Focus
121
138
 
122
139
  Focus helper functions to easily select focusable DOM nodes
package/helpers/flags.js CHANGED
@@ -1,16 +1,45 @@
1
+ const knownFlags = new Map();
1
2
  const flagOverrides = new Map();
2
3
 
3
4
  export function getFlag(key, defaultValue) {
5
+ let value;
4
6
  if (flagOverrides.has(key)) {
5
- return flagOverrides.get(key);
7
+ value = flagOverrides.get(key);
8
+ } else {
9
+ value = globalThis.D2L?.LP?.Web?.UI?.Flags.Flag(key, defaultValue) ?? defaultValue;
6
10
  }
7
- return globalThis.D2L?.LP?.Web?.UI?.Flags.Flag(key, defaultValue) ?? defaultValue;
11
+ addKnownFlag(key, value, defaultValue);
12
+ return value;
13
+ }
14
+
15
+ export function getFlagOverrides() {
16
+ return flagOverrides;
17
+ }
18
+
19
+ export function getKnownFlags() {
20
+ return knownFlags;
8
21
  }
9
22
 
10
23
  export function mockFlag(key, value) {
24
+ if (knownFlags.has(key)) console.warn(`mockFlag called after getFlag for '${key}'. This is likely to result in unexpected behaviour.`);
11
25
  flagOverrides.set(key, value);
12
26
  }
13
27
 
14
28
  export function resetFlag(key) {
15
29
  flagOverrides.delete(key);
16
30
  }
31
+
32
+ let dispatchingKnownFlags = false;
33
+
34
+ function addKnownFlag(key, value, defaultValue) {
35
+ if (!knownFlags.has(key)) knownFlags.set(key, { value, defaultValue });
36
+
37
+ if (dispatchingKnownFlags) return;
38
+ dispatchingKnownFlags = true;
39
+ setTimeout(() => {
40
+ globalThis.document.dispatchEvent(new CustomEvent('d2l-flags-known', {
41
+ detail: { flagOverrides, knownFlags }
42
+ }));
43
+ dispatchingKnownFlags = false;
44
+ });
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.173.0",
3
+ "version": "3.174.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",