@justeattakeaway/pie-switch 2.4.1 → 2.5.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/README.md +1 -0
- package/custom-elements.json +34 -13
- package/dist/index.d.ts +14 -8
- package/dist/index.js +250 -231
- package/dist/react.d.ts +14 -8
- package/package.json +5 -5
- package/src/defs.ts +6 -0
- package/src/index.ts +63 -33
- package/src/switch.scss +9 -12
package/dist/react.d.ts
CHANGED
|
@@ -36,11 +36,13 @@ declare class PieSwitch_2 extends PieSwitch_base implements SwitchProps, PIEInpu
|
|
|
36
36
|
labelPlacement: "leading" | "trailing";
|
|
37
37
|
aria: SwitchProps['aria'];
|
|
38
38
|
checked: boolean;
|
|
39
|
+
defaultChecked: boolean;
|
|
39
40
|
required: boolean;
|
|
40
41
|
value: string;
|
|
41
42
|
name: SwitchProps['name'];
|
|
42
43
|
disabled: boolean;
|
|
43
44
|
private input;
|
|
45
|
+
private switchBody;
|
|
44
46
|
focusTarget: HTMLElement;
|
|
45
47
|
private _abortController;
|
|
46
48
|
private _isAnimationAllowed;
|
|
@@ -75,6 +77,11 @@ declare class PieSwitch_2 extends PieSwitch_base implements SwitchProps, PIEInpu
|
|
|
75
77
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setCustomValidity
|
|
76
78
|
*/
|
|
77
79
|
setCustomValidity(message: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Called when the containing form is reset.
|
|
82
|
+
* Resets checked state back to defaultChecked and emits a change event when needed.
|
|
83
|
+
*/
|
|
84
|
+
formResetCallback(): void;
|
|
78
85
|
/**
|
|
79
86
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
80
87
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
@@ -86,15 +93,9 @@ declare class PieSwitch_2 extends PieSwitch_base implements SwitchProps, PIEInpu
|
|
|
86
93
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage
|
|
87
94
|
*/
|
|
88
95
|
get validationMessage(): string;
|
|
89
|
-
/**
|
|
90
|
-
* If a label is provided, renders it if `labelPlacement` matches the given position.
|
|
91
|
-
* If no label is provided, or `labelPlacement` does not match the given position, nothing is rendered.
|
|
92
|
-
*
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
private renderSwitchLabel;
|
|
96
96
|
private renderAriaDescription;
|
|
97
|
-
|
|
97
|
+
private renderSwitchLabel;
|
|
98
|
+
render(): TemplateResult;
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
declare const PieSwitch_base: GenericConstructor<FormControlInterface> & typeof PieElement;
|
|
@@ -115,6 +116,11 @@ export declare interface SwitchProps {
|
|
|
115
116
|
* Same as the HTML checked attribute - indicates whether the switch is on or off
|
|
116
117
|
*/
|
|
117
118
|
checked?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* The default checked state of the switch (not necessarily the same as the current checked state).
|
|
121
|
+
* Used when the switch is part of a form that is reset.
|
|
122
|
+
*/
|
|
123
|
+
defaultChecked?: boolean;
|
|
118
124
|
/**
|
|
119
125
|
* Same as the HTML required attribute - indicates whether the switch must be turned or not
|
|
120
126
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justeattakeaway/pie-switch",
|
|
3
3
|
"description": "PIE Design System Switch built using Web Components",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/justeattakeaway/pie",
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"license": "Apache-2.0",
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@justeattakeaway/pie-components-config": "0.21.3",
|
|
47
|
-
"@justeattakeaway/pie-css": "1.
|
|
48
|
-
"@justeattakeaway/pie-monorepo-utils": "0.9.
|
|
47
|
+
"@justeattakeaway/pie-css": "1.2.0",
|
|
48
|
+
"@justeattakeaway/pie-monorepo-utils": "0.9.6",
|
|
49
49
|
"@justeattakeaway/pie-wrapper-react": "0.14.5"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@justeattakeaway/pie-icons-webc": "1.25.
|
|
53
|
-
"@justeattakeaway/pie-webc-core": "
|
|
52
|
+
"@justeattakeaway/pie-icons-webc": "1.25.1",
|
|
53
|
+
"@justeattakeaway/pie-webc-core": "15.0.0",
|
|
54
54
|
"element-internals-polyfill": "1.3.11"
|
|
55
55
|
},
|
|
56
56
|
"customElements": "custom-elements.json",
|
package/src/defs.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface SwitchProps {
|
|
|
16
16
|
* Same as the HTML checked attribute - indicates whether the switch is on or off
|
|
17
17
|
*/
|
|
18
18
|
checked?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The default checked state of the switch (not necessarily the same as the current checked state).
|
|
21
|
+
* Used when the switch is part of a form that is reset.
|
|
22
|
+
*/
|
|
23
|
+
defaultChecked?: boolean;
|
|
19
24
|
/**
|
|
20
25
|
* Same as the HTML required attribute - indicates whether the switch must be turned or not
|
|
21
26
|
*/
|
|
@@ -53,6 +58,7 @@ export type DefaultProps = ComponentDefaultProps<SwitchProps, keyof Omit<SwitchP
|
|
|
53
58
|
|
|
54
59
|
export const defaultProps: DefaultProps = {
|
|
55
60
|
checked: false,
|
|
61
|
+
defaultChecked: false,
|
|
56
62
|
disabled: false,
|
|
57
63
|
labelPlacement: 'leading',
|
|
58
64
|
required: false,
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
html, unsafeCSS, nothing,
|
|
3
3
|
} from 'lit';
|
|
4
|
+
import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
|
|
4
5
|
import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
|
|
5
6
|
import { property, query, state } from 'lit/decorators.js';
|
|
6
7
|
import { classMap } from 'lit/directives/class-map.js';
|
|
7
8
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
9
|
+
import { live } from 'lit/directives/live.js';
|
|
8
10
|
import 'element-internals-polyfill';
|
|
9
11
|
|
|
10
12
|
import {
|
|
@@ -44,6 +46,9 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
44
46
|
@property({ type: Boolean, reflect: true })
|
|
45
47
|
public checked = defaultProps.checked;
|
|
46
48
|
|
|
49
|
+
@property({ type: Boolean, reflect: true })
|
|
50
|
+
public defaultChecked = defaultProps.defaultChecked;
|
|
51
|
+
|
|
47
52
|
@property({ type: Boolean, reflect: true })
|
|
48
53
|
public required = defaultProps.required;
|
|
49
54
|
|
|
@@ -59,7 +64,10 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
59
64
|
@query('input[type="checkbox"]')
|
|
60
65
|
private input!: HTMLInputElement;
|
|
61
66
|
|
|
62
|
-
@query('
|
|
67
|
+
@query('.c-switch')
|
|
68
|
+
private switchBody!: HTMLElement;
|
|
69
|
+
|
|
70
|
+
@query('label, input[type="checkbox"]')
|
|
63
71
|
public focusTarget!: HTMLElement;
|
|
64
72
|
|
|
65
73
|
private _abortController!: AbortController;
|
|
@@ -83,10 +91,18 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
83
91
|
const { signal } = this._abortController;
|
|
84
92
|
|
|
85
93
|
this.addEventListener('click', (event: Event) => {
|
|
94
|
+
const [source] = event.composedPath();
|
|
95
|
+
|
|
96
|
+
if (this.disabled || source === this.input) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
86
100
|
// Only programmatically click the input if the explicit target
|
|
87
101
|
// of the click was the host element itself (e.g., via an external label).
|
|
88
102
|
// This ignores clicks bubbling up from the internal shadow DOM and prevents loops.
|
|
89
|
-
|
|
103
|
+
// Also forward clicks from the visual switch body when no internal label exists.
|
|
104
|
+
const isInsideSwitchBody = !this.label && event.composedPath().includes(this.switchBody);
|
|
105
|
+
if (source === this || isInsideSwitchBody) {
|
|
90
106
|
this.input.click();
|
|
91
107
|
}
|
|
92
108
|
}, { signal });
|
|
@@ -166,6 +182,23 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
166
182
|
this._internals.setValidity(this.validity, this.validationMessage, this.input);
|
|
167
183
|
}
|
|
168
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Called when the containing form is reset.
|
|
187
|
+
* Resets checked state back to defaultChecked and emits a change event when needed.
|
|
188
|
+
*/
|
|
189
|
+
public formResetCallback () : void {
|
|
190
|
+
if (this.checked === this.defaultChecked) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.checked = this.defaultChecked;
|
|
195
|
+
|
|
196
|
+
const changeEvent = new Event('change', { bubbles: true, composed: true });
|
|
197
|
+
this.dispatchEvent(changeEvent);
|
|
198
|
+
|
|
199
|
+
this.handleFormAssociation();
|
|
200
|
+
}
|
|
201
|
+
|
|
169
202
|
/**
|
|
170
203
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
171
204
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
@@ -183,36 +216,12 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
183
216
|
return this.input.validationMessage;
|
|
184
217
|
}
|
|
185
218
|
|
|
186
|
-
/**
|
|
187
|
-
* If a label is provided, renders it if `labelPlacement` matches the given position.
|
|
188
|
-
* If no label is provided, or `labelPlacement` does not match the given position, nothing is rendered.
|
|
189
|
-
*
|
|
190
|
-
* @private
|
|
191
|
-
*/
|
|
192
|
-
private renderSwitchLabel (placement : SwitchProps['labelPlacement']) {
|
|
193
|
-
const { label, labelPlacement } = this;
|
|
194
|
-
|
|
195
|
-
if (!label || labelPlacement !== placement) {
|
|
196
|
-
return nothing;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Using aria-hidden here to prevent the label from potentially being narrated twice by screen readers such as Apple VoiceOver.
|
|
200
|
-
// Instead, we apply the label as an aria-label attribute on the input (if no aria.label prop is provided).
|
|
201
|
-
return html`
|
|
202
|
-
<span
|
|
203
|
-
aria-hidden="true"
|
|
204
|
-
data-test-id="switch-label-${labelPlacement}"
|
|
205
|
-
class="c-switch-label">
|
|
206
|
-
${label}
|
|
207
|
-
</span>`;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
219
|
private renderAriaDescription () {
|
|
211
220
|
if (!this.aria?.describedBy) {
|
|
212
221
|
return nothing;
|
|
213
222
|
}
|
|
214
223
|
|
|
215
|
-
// we apply aria-hidden to the element containing the description because it
|
|
224
|
+
// we apply aria-hidden to the element containing the description because it prevents some screen readers such as Apple VoiceOver from announcing the description once
|
|
216
225
|
// on the input and again separately. The description is still announced once, when the input is focused/selected.
|
|
217
226
|
return html`
|
|
218
227
|
<div
|
|
@@ -224,9 +233,28 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
224
233
|
</div>`;
|
|
225
234
|
}
|
|
226
235
|
|
|
236
|
+
private renderSwitchLabel () {
|
|
237
|
+
const { label, labelPlacement } = this;
|
|
238
|
+
|
|
239
|
+
if (!label) {
|
|
240
|
+
return nothing;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Using aria-hidden here to prevent the label from potentially being narrated twice by screen readers such as Apple VoiceOver.
|
|
244
|
+
// Instead, we apply the label as an aria-label attribute on the input (if no aria.label prop is provided).
|
|
245
|
+
return html`
|
|
246
|
+
<span
|
|
247
|
+
aria-hidden="true"
|
|
248
|
+
data-test-id="switch-label-${labelPlacement}"
|
|
249
|
+
class="c-switch-label">
|
|
250
|
+
${label}
|
|
251
|
+
</span>`;
|
|
252
|
+
}
|
|
253
|
+
|
|
227
254
|
render () {
|
|
228
255
|
const {
|
|
229
256
|
label,
|
|
257
|
+
labelPlacement,
|
|
230
258
|
aria,
|
|
231
259
|
checked,
|
|
232
260
|
disabled,
|
|
@@ -237,13 +265,15 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
237
265
|
const classes = {
|
|
238
266
|
'c-switch-wrapper': true,
|
|
239
267
|
'c-switch-wrapper--allow-animation': _isAnimationAllowed,
|
|
268
|
+
[`c-switch-wrapper--label-${labelPlacement}`]: true,
|
|
240
269
|
};
|
|
241
270
|
|
|
242
|
-
|
|
243
|
-
|
|
271
|
+
const tag = unsafeStatic(label ? 'label' : 'div');
|
|
272
|
+
|
|
273
|
+
return staticHtml`
|
|
274
|
+
<${tag}
|
|
244
275
|
class="${classMap(classes)}"
|
|
245
276
|
?disabled=${disabled}>
|
|
246
|
-
${this.renderSwitchLabel('leading')}
|
|
247
277
|
<div
|
|
248
278
|
data-test-id="switch-component"
|
|
249
279
|
class="c-switch"
|
|
@@ -254,7 +284,7 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
254
284
|
type="checkbox"
|
|
255
285
|
class="c-switch-input"
|
|
256
286
|
.required=${required}
|
|
257
|
-
.checked="${checked}"
|
|
287
|
+
.checked="${live(checked)}"
|
|
258
288
|
.disabled="${disabled}"
|
|
259
289
|
@change="${this.handleChange}"
|
|
260
290
|
aria-label="${ifDefined(aria?.label || label)}"
|
|
@@ -263,9 +293,9 @@ export class PieSwitch extends FormControlMixin(DelegatesFocusMixin(PieElement))
|
|
|
263
293
|
${checked ? html`<icon-check></icon-check>` : nothing}
|
|
264
294
|
</div>
|
|
265
295
|
</div>
|
|
266
|
-
${this.renderSwitchLabel(
|
|
296
|
+
${this.renderSwitchLabel()}
|
|
267
297
|
${this.renderAriaDescription()}
|
|
268
|
-
|
|
298
|
+
</${tag}>`;
|
|
269
299
|
}
|
|
270
300
|
}
|
|
271
301
|
|
package/src/switch.scss
CHANGED
|
@@ -69,17 +69,7 @@
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
.c-switch-input {
|
|
72
|
-
|
|
73
|
-
width: 1px;
|
|
74
|
-
height: 1px;
|
|
75
|
-
margin: -1px;
|
|
76
|
-
padding: 0;
|
|
77
|
-
overflow: hidden;
|
|
78
|
-
clip: rect(0, 0, 0, 0);
|
|
79
|
-
border: 0;
|
|
80
|
-
left: 50%;
|
|
81
|
-
transform: translateX(-50%) translateY(-50%);
|
|
82
|
-
bottom: 0;
|
|
72
|
+
@include p.visually-hidden;
|
|
83
73
|
|
|
84
74
|
&:disabled {
|
|
85
75
|
background-color: transparent;
|
|
@@ -131,6 +121,13 @@
|
|
|
131
121
|
@include p.visually-hidden;
|
|
132
122
|
}
|
|
133
123
|
|
|
124
|
+
.c-switch-wrapper--label-leading {
|
|
125
|
+
flex-direction: row-reverse;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.c-switch-wrapper--label-trailing {
|
|
129
|
+
flex-direction: row;
|
|
130
|
+
}
|
|
134
131
|
|
|
135
132
|
.c-switch-wrapper--allow-animation {
|
|
136
133
|
/* stylelint-disable-next-line no-descending-specificity */
|
|
@@ -166,4 +163,4 @@
|
|
|
166
163
|
.c-switch-input:checked + .c-switch-control {
|
|
167
164
|
transform: translateX(calc(-1 * var(--switch-translation)));
|
|
168
165
|
}
|
|
169
|
-
}
|
|
166
|
+
}
|