@brightspace-ui/core 3.49.1 → 3.50.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -19,7 +19,7 @@ npm install @brightspace-ui/core
19
19
  * [Alert](components/alert/): alert components for displaying important information
20
20
  * [Breadcrumbs](components/breadcrumbs/): component to help users understand where they are within an application
21
21
  * [Backdrop](components/backdrop/): component for displaying backdrop behind a target element
22
- * [Buttons](components/button/): normal, primary, icon and subtle buttons
22
+ * [Buttons](components/button/): normal, primary, icon, subtle, and toggle buttons
23
23
  * [Calendar](components/calendar/): calendar component
24
24
  * [Card](components/card/): card components
25
25
  * [Colors](components/colors/): color palette
@@ -143,6 +143,34 @@ The `d2l-button-icon` element can be used just like the native `button`, for ins
143
143
  </d2l-button-icon>
144
144
  ```
145
145
 
146
+ ## Toggle Button [d2l-button-toggle]
147
+
148
+ The `d2l-button-toggle` element is a container for buttons that toggle a `pressed` state. The component will automatically show or hide the buttons and manage focus based on the `pressed` state. Simply place a `d2l-button-icon` or `d2l-button-subtle` element in each of the `not-pressed` and `pressed` slots. Each button should describe the state and action the user can take.
149
+
150
+ <!-- docs: demo code properties name:d2l-button-toggle sandboxTitle:'Toggle Button' -->
151
+ ```html
152
+ <script type="module">
153
+ import '@brightspace-ui/core/components/button/button-subtle.js';
154
+ import '@brightspace-ui/core/components/button/button-toggle.js';
155
+ </script>
156
+ <d2l-button-toggle pressed>
157
+ <d2l-button-subtle slot="not-pressed" icon="tier1:lock-unlock" text="Unlocked" description="Click to lock."></d2l-button-subtle>
158
+ <d2l-button-subtle slot="pressed" icon="tier1:lock-locked" text="Locked" description="Click to unlock."></d2l-button-subtle>
159
+ </d2l-button-toggle>
160
+ ```
161
+
162
+ <!-- docs: start hidden content -->
163
+ ### Properties
164
+
165
+ | Property | Type | Description |
166
+ |--|--|--|
167
+ | `pressed` | Boolean | Pressed state |
168
+
169
+ ### Events
170
+
171
+ - `d2l-button-toggle-change`: dispatched when the `pressed` state changes
172
+ <!-- docs: end hidden content -->
173
+
146
174
  ## Add Button [d2l-button-add]
147
175
 
148
176
  The `d2l-button-add` is for quickly adding new items at a specific location, such as when adding items to a curated list. Since the Add button is meant to be subtle, it should always be used in combination with more obvious methods to add items (like a menu or primary button).
@@ -220,6 +248,9 @@ Daylight buttons rely on standard button semantics to ensure a smooth experience
220
248
  * For [Icon Buttons](#d2l-button-icon) where there is no visible label, `text` will be displayed in a tooltip
221
249
  * If both `text` and `aria-label` are used, then `aria-label` will be used as the primary label while `text` will be used in a [tooltip](../../components/tooltip)
222
250
 
251
+ * [Toggle buttons](#d2l-button-toggle) should describe the current state and the action the user can perform. As such, `aria-pressed` should not be used on the buttons as per [W3C's Button Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/#:~:text=Alternatively%2C%20if%20the%20design%20were%20to%20call%20for%20the%20button%20label%20to%20change%20from%20%22Mute%22%20to%20%22Unmute%2C%22%20the%20aria%2Dpressed%20attribute%20would%20not%20be%20needed.).
252
+ * Example: "Unpinned, click to pin" and "Pinned, click to unpin"
253
+
223
254
  * [Floating Buttons](#d2l-floating-buttons) maintain their position in the document's structure, despite sticking to the bottom of the viewport, so the tab order is unaffected and the effect is imperceptible to screen reader users
224
255
  * Be cautious when using `always-float`, since screen magnifier users may find it difficult to locate the buttons at the bottom of a large viewport
225
256
 
@@ -0,0 +1,97 @@
1
+ import { css, html, LitElement } from 'lit';
2
+
3
+ /**
4
+ * A button container component for button toggles.
5
+ */
6
+ class ButtonToggle extends LitElement {
7
+
8
+ static get properties() {
9
+ return {
10
+ /**
11
+ * Pressed state
12
+ * @type {boolean}
13
+ */
14
+ pressed: { type: Boolean, reflect: true }
15
+ };
16
+ }
17
+
18
+ static get styles() {
19
+ return css`
20
+ :host {
21
+ display: inline-block;
22
+ }
23
+ :host([hidden]) {
24
+ display: none;
25
+ }
26
+ ::slotted(:not(d2l-button-icon, d2l-button-subtle)),
27
+ :host slot[name="pressed"],
28
+ :host([pressed]) slot[name="not-pressed"] {
29
+ display: none;
30
+ }
31
+ :host slot[name="not-pressed"],
32
+ :host([pressed]) slot[name="pressed"] {
33
+ display: contents;
34
+ }
35
+ `;
36
+ }
37
+
38
+ constructor() {
39
+ super();
40
+ this.pressed = false;
41
+ }
42
+
43
+ firstUpdated(changedProperties) {
44
+ super.firstUpdated(changedProperties);
45
+ if (this._focusOnFirstRender) {
46
+ this._focusOnFirstRender = false;
47
+ this.focus();
48
+ }
49
+ }
50
+
51
+ render() {
52
+ return html`
53
+ <slot @click="${this._handleNotPressedClick}" name="not-pressed"></slot>
54
+ <slot @click="${this._handlePressedClick}" name="pressed"></slot>
55
+ `;
56
+ }
57
+
58
+ updated(changedProperties) {
59
+ super.updated(changedProperties);
60
+
61
+ if (changedProperties.get('pressed') === undefined) return;
62
+
63
+ /** Dispatched when the pressed state changes */
64
+ this.dispatchEvent(new CustomEvent('d2l-button-toggle-change'));
65
+ }
66
+
67
+ focus() {
68
+ if (!this.hasUpdated) {
69
+ this._focusOnFirstRender = true;
70
+ return;
71
+ }
72
+
73
+ const elem = this.shadowRoot.querySelector(this.pressed ? 'slot[name="pressed"]' : 'slot[name="not-pressed"]').assignedNodes()[0];
74
+ if (!elem) {
75
+ throw new Error('d2l-button-toggle: no button to focus');
76
+ }
77
+
78
+ elem.focus();
79
+ }
80
+
81
+ async _handleClick(pressed) {
82
+ this.pressed = pressed;
83
+ await this.updateComplete;
84
+ this.focus();
85
+ }
86
+
87
+ _handleNotPressedClick() {
88
+ this._handleClick(true);
89
+ }
90
+
91
+ _handlePressedClick() {
92
+ this._handleClick(false);
93
+ }
94
+
95
+ }
96
+
97
+ customElements.define('d2l-button-toggle', ButtonToggle);
@@ -0,0 +1,60 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta charset="UTF-8">
6
+ <link rel="stylesheet" href="../../demo/styles.css" type="text/css">
7
+ <script type="module">
8
+ import '../../demo/demo-page.js';
9
+ import '../button-icon.js';
10
+ import '../button-subtle.js';
11
+ import '../button-toggle.js';
12
+ </script>
13
+ </head>
14
+ <body unresolved>
15
+
16
+ <d2l-demo-page page-title="d2l-button-toggle">
17
+
18
+ <h2>Toggle Button (using d2l-button-icon)</h2>
19
+
20
+ <d2l-demo-snippet>
21
+ <template>
22
+ <d2l-button-toggle id="toggle-button-icon">
23
+ <d2l-button-icon slot="not-pressed" icon="tier1:pin-hollow" text="Unpinned, click to pin."></d2l-button-icon>
24
+ <d2l-button-icon slot="pressed" icon="tier1:pin-filled" text="Pinned, click to unpin."></d2l-button-icon>
25
+ </d2l-button-toggle>
26
+ <script>
27
+ document.querySelector('#toggle-button-icon').addEventListener('d2l-button-toggle-change', e => console.log(e));
28
+ </script>
29
+ </template>
30
+ </d2l-demo-snippet>
31
+
32
+ <h2>Toggle Button (using d2l-button-subtle)</h2>
33
+
34
+ <d2l-demo-snippet>
35
+ <template>
36
+ <d2l-button-toggle id="toggle-button-subtle" pressed>
37
+ <d2l-button-subtle slot="not-pressed" icon="tier1:lock-unlock" text="Unlocked" description="Click to lock."></d2l-button-subtle>
38
+ <d2l-button-subtle slot="pressed" icon="tier1:lock-locked" text="Locked" description="Click to unlock."></d2l-button-subtle>
39
+ </d2l-button-toggle>
40
+ <script>
41
+ document.querySelector('#toggle-button-subtle').addEventListener('d2l-button-toggle-change', e => console.log(e));
42
+ </script>
43
+ </template>
44
+ </d2l-demo-snippet>
45
+
46
+ <h2>Toggle Button (disabled)</h2>
47
+
48
+ <d2l-demo-snippet>
49
+ <template>
50
+ <d2l-button-toggle pressed>
51
+ <d2l-button-subtle slot="not-pressed" disabled icon="tier1:subscribe-hollow" text="Not Subscribed" description="Click to subscribe."></d2l-button-subtle>
52
+ <d2l-button-subtle slot="pressed" disabled icon="tier1:subscribe-filled" text="Subscribed" description="Click to unsubscribe."></d2l-button-subtle>
53
+ </d2l-button-toggle>
54
+ </template>
55
+ </d2l-demo-snippet>
56
+
57
+ </d2l-demo-page>
58
+
59
+ </body>
60
+ </html>
@@ -717,6 +717,34 @@
717
717
  }
718
718
  ]
719
719
  },
720
+ {
721
+ "name": "d2l-button-toggle",
722
+ "path": "./components/button/button-toggle.js",
723
+ "description": "A button container component for button toggles.",
724
+ "attributes": [
725
+ {
726
+ "name": "pressed",
727
+ "description": "Pressed state",
728
+ "type": "boolean",
729
+ "default": "false"
730
+ }
731
+ ],
732
+ "properties": [
733
+ {
734
+ "name": "pressed",
735
+ "attribute": "pressed",
736
+ "description": "Pressed state",
737
+ "type": "boolean",
738
+ "default": "false"
739
+ }
740
+ ],
741
+ "events": [
742
+ {
743
+ "name": "d2l-button-toggle-change",
744
+ "description": "Dispatched when the pressed state changes"
745
+ }
746
+ ]
747
+ },
720
748
  {
721
749
  "name": "d2l-button",
722
750
  "path": "./components/button/button.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.49.1",
3
+ "version": "3.50.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",