@justeattakeaway/pie-switch 0.18.4 → 0.20.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/dist/react.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { CSSResult } from 'lit';
2
2
  import type { EventName } from '@lit/react';
3
3
  import type { LitElement } from 'lit';
4
+ import type { PropertyValues } from 'lit';
4
5
  import type { ReactWebComponent } from '@lit/react';
5
6
  import type { TemplateResult } from 'lit';
6
7
 
@@ -18,24 +19,70 @@ export declare const labelPlacements: readonly ["leading", "trailing"];
18
19
  *
19
20
  * @constant
20
21
  */
21
- export declare const ON_SWITCH_CHANGED_EVENT = "pie-switch-changed";
22
+ export declare const ON_SWITCH_CHANGED_EVENT = "change";
22
23
 
23
24
  export declare const PieSwitch: ReactWebComponent<PieSwitch_2, {
24
- onPieSwitchChanged: EventName<CustomEvent<any>>;
25
+ onInvalid: EventName<Event>;
26
+ onChange: EventName<CustomEvent<any>>;
25
27
  }>;
26
28
 
27
29
  /**
28
30
  * @tagname pie-switch
29
- * @event {CustomEvent} pie-switch-changed - when the switch checked state is changed.
31
+ * @event {CustomEvent} change - when the switch checked state is changed.
30
32
  */
31
33
  declare class PieSwitch_2 extends PieSwitch_base implements SwitchProps {
34
+ static formAssociated: boolean;
35
+ private readonly _internals;
36
+ private input?;
37
+ constructor();
38
+ protected firstUpdated(_changedProperties: PropertyValues<this>): void;
39
+ protected updated(_changedProperties: PropertyValues<this>): void;
32
40
  label?: string;
33
41
  labelPlacement: SwitchProps['labelPlacement'];
34
42
  aria: AriaProps;
35
- isChecked: boolean;
43
+ checked: boolean;
44
+ required: boolean;
45
+ value: string;
46
+ name?: string;
36
47
  isDisabled: boolean;
37
48
  static styles: CSSResult;
49
+ /**
50
+ * Ensures that the form value and validation state are in sync with the component.
51
+ */
52
+ private handleFormAssociation;
53
+ /**
54
+ * The onChange function updates the checkbox state and emits an event for consumers.
55
+ * @param {Event} event - This should be the change event that was listened for on an input element with `type="checkbox"`.
56
+ */
38
57
  onChange(event: Event): void;
58
+ /**
59
+ * Returns a boolean value which indicates validity of the value of the component. If the value is invalid, this method also fires the invalid event on the component.
60
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checkValidity
61
+ * @returns boolean
62
+ */
63
+ checkValidity(): boolean;
64
+ /**
65
+ * If the value is invalid, this method also fires the invalid event on the element, and (if the event isn't canceled) reports the problem to the user.
66
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/reportValidity
67
+ * @returns boolean
68
+ */
69
+ reportValidity(): boolean;
70
+ /**
71
+ * Allows a consumer to set a custom validation message on the switch. An empty string counts as valid.
72
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setCustomValidity
73
+ */
74
+ setCustomValidity(message: string): void;
75
+ /**
76
+ * (Read-only) returns a ValidityState with the validity states that this element is in.
77
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
78
+ */
79
+ get validity(): ValidityState;
80
+ /**
81
+ * (Read-only) Returns a string representing a localized message that describes the validation constraints that the control does not satisfy (if any).
82
+ * This string is empty if the component is valid.
83
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage
84
+ */
85
+ get validationMessage(): string;
39
86
  /**
40
87
  * Renders the label for a switch if provided.
41
88
  * if invalid value is passed, nothing gets rendered
@@ -58,9 +105,13 @@ export declare interface SwitchProps {
58
105
  /**
59
106
  * Same as the HTML checked attribute - indicates whether the switch is on or off
60
107
  */
61
- isChecked?: boolean;
108
+ checked?: boolean;
109
+ /**
110
+ * Same as the HTML required attribute - indicates whether the switch must be turned or not
111
+ */
112
+ required: boolean;
62
113
  /**
63
- * Same as the HTML checked attribute - indicates whether the switch disabled or not
114
+ * Same as the HTML disabled attribute - indicates whether the switch disabled or not
64
115
  */
65
116
  isDisabled?: boolean;
66
117
  /**
@@ -71,6 +122,14 @@ export declare interface SwitchProps {
71
122
  * The placement of the label such as leading or trailing
72
123
  */
73
124
  labelPlacement?: LabelPlacement;
125
+ /**
126
+ * Same as the HTML name attribute - indicates the name of the switch (for use with forms)
127
+ */
128
+ name?: string;
129
+ /**
130
+ * Same as the HTML value attribute - indicates the value of the switch (for use with forms). Defaults to 'on'.
131
+ */
132
+ value: string;
74
133
  }
75
134
 
76
135
  export { }
package/dist/react.js CHANGED
@@ -1,23 +1,24 @@
1
1
  import * as e from "react";
2
2
  import { createComponent as t } from "@lit/react";
3
3
  import { PieSwitch as i } from "./index.js";
4
- import { ON_SWITCH_CHANGED_EVENT as w, labelPlacements as l } from "./index.js";
4
+ import { ON_SWITCH_CHANGED_EVENT as h, labelPlacements as w } from "./index.js";
5
5
  import "lit";
6
6
  import "lit/decorators.js";
7
7
  import "@justeattakeaway/pie-webc-core";
8
8
  import "@justeattakeaway/pie-icons-webc/IconCheck";
9
- const s = t({
9
+ const c = t({
10
10
  displayName: "PieSwitch",
11
11
  elementClass: i,
12
12
  react: e,
13
13
  tagName: "pie-switch",
14
14
  events: {
15
- onPieSwitchChanged: "pie-switch-changed"
15
+ onInvalid: "invalid",
16
+ onChange: "change"
16
17
  // when the switch checked state is changed.
17
18
  }
18
19
  });
19
20
  export {
20
- w as ON_SWITCH_CHANGED_EVENT,
21
- s as PieSwitch,
22
- l as labelPlacements
21
+ h as ON_SWITCH_CHANGED_EVENT,
22
+ c as PieSwitch,
23
+ w as labelPlacements
23
24
  };
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": "0.18.4",
4
+ "version": "0.20.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -28,11 +28,12 @@
28
28
  "author": "Just Eat Takeaway.com - Design System Team",
29
29
  "license": "Apache-2.0",
30
30
  "devDependencies": {
31
- "@justeattakeaway/pie-components-config": "0.6.1"
31
+ "@justeattakeaway/pie-components-config": "0.7.0"
32
32
  },
33
33
  "dependencies": {
34
34
  "@justeattakeaway/pie-icons-webc": "0.15.0",
35
- "@justeattakeaway/pie-webc-core": "0.13.0"
35
+ "@justeattakeaway/pie-webc-core": "0.13.0",
36
+ "element-internals-polyfill": "1.3.9"
36
37
  },
37
38
  "volta": {
38
39
  "extends": "../../../package.json"
package/src/defs.ts CHANGED
@@ -15,9 +15,13 @@ export interface SwitchProps {
15
15
  /**
16
16
  * Same as the HTML checked attribute - indicates whether the switch is on or off
17
17
  */
18
- isChecked?: boolean;
18
+ checked?: boolean;
19
19
  /**
20
- * Same as the HTML checked attribute - indicates whether the switch disabled or not
20
+ * Same as the HTML required attribute - indicates whether the switch must be turned or not
21
+ */
22
+ required: boolean;
23
+ /**
24
+ * Same as the HTML disabled attribute - indicates whether the switch disabled or not
21
25
  */
22
26
  isDisabled?: boolean;
23
27
  /**
@@ -28,6 +32,14 @@ export interface SwitchProps {
28
32
  * The placement of the label such as leading or trailing
29
33
  */
30
34
  labelPlacement?: LabelPlacement;
35
+ /**
36
+ * Same as the HTML name attribute - indicates the name of the switch (for use with forms)
37
+ */
38
+ name?: string;
39
+ /**
40
+ * Same as the HTML value attribute - indicates the value of the switch (for use with forms). Defaults to 'on'.
41
+ */
42
+ value: string;
31
43
  }
32
44
 
33
45
  /**
@@ -35,4 +47,4 @@ export interface SwitchProps {
35
47
  *
36
48
  * @constant
37
49
  */
38
- export const ON_SWITCH_CHANGED_EVENT = 'pie-switch-changed';
50
+ export const ON_SWITCH_CHANGED_EVENT = 'change';
package/src/index.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import {
2
- LitElement, html, unsafeCSS, nothing, TemplateResult,
2
+ LitElement, html, unsafeCSS, nothing, TemplateResult, PropertyValues,
3
3
  } from 'lit';
4
- import { property } from 'lit/decorators.js';
4
+ import { property, query } from 'lit/decorators.js';
5
5
  import { RtlMixin, validPropertyValues, defineCustomElement } from '@justeattakeaway/pie-webc-core';
6
6
  import styles from './switch.scss?inline';
7
7
  import {
8
8
  SwitchProps, ON_SWITCH_CHANGED_EVENT, AriaProps, labelPlacements,
9
9
  } from './defs';
10
+ import 'element-internals-polyfill';
10
11
  import '@justeattakeaway/pie-icons-webc/IconCheck';
11
12
 
12
13
  // Valid values available to consumers
@@ -16,10 +17,39 @@ const componentSelector = 'pie-switch';
16
17
 
17
18
  /**
18
19
  * @tagname pie-switch
19
- * @event {CustomEvent} pie-switch-changed - when the switch checked state is changed.
20
+ * @event {CustomEvent} change - when the switch checked state is changed.
20
21
  */
21
22
 
22
23
  export class PieSwitch extends RtlMixin(LitElement) implements SwitchProps {
24
+ // TODO - we may want to consider making the element internals code reusable for other form controls.
25
+ static formAssociated = true;
26
+
27
+ private readonly _internals: ElementInternals;
28
+
29
+ @query('input[type="checkbox"]')
30
+ private input?: HTMLInputElement;
31
+
32
+ constructor () {
33
+ super();
34
+ this._internals = this.attachInternals();
35
+ }
36
+
37
+ protected firstUpdated (_changedProperties: PropertyValues<this>): void {
38
+ super.firstUpdated(_changedProperties);
39
+
40
+ this.handleFormAssociation();
41
+ // This ensures that invalid events triggered by checkValidity() are propagated to the custom element
42
+ // for consumers to listen to: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checkValidity
43
+ this.input?.addEventListener('invalid', (event) => {
44
+ this.dispatchEvent(new Event('invalid', event));
45
+ });
46
+ }
47
+
48
+ protected updated (_changedProperties: PropertyValues<this>): void {
49
+ super.updated(_changedProperties);
50
+ this.handleFormAssociation();
51
+ }
52
+
23
53
  @property({ type: String })
24
54
  public label?: string;
25
55
 
@@ -31,25 +61,102 @@ export class PieSwitch extends RtlMixin(LitElement) implements SwitchProps {
31
61
  public aria!: AriaProps;
32
62
 
33
63
  @property({ type: Boolean, reflect: true })
34
- public isChecked = false;
64
+ public checked = false;
65
+
66
+ @property({ type: Boolean, reflect: true })
67
+ public required = false;
68
+
69
+ @property({ type: String })
70
+ public value = 'on';
71
+
72
+ @property({ type: String })
73
+ public name?: string;
35
74
 
36
75
  @property({ type: Boolean, reflect: true })
37
76
  public isDisabled = false;
38
77
 
39
78
  static styles = unsafeCSS(styles);
40
79
 
80
+ /**
81
+ * Ensures that the form value and validation state are in sync with the component.
82
+ */
83
+ private handleFormAssociation () : void {
84
+ const isFormAssociated = !!this._internals.form && !!this.name && !!this.value;
85
+ if (isFormAssociated) {
86
+ if (this.isDisabled) {
87
+ this._internals.setFormValue(null);
88
+ this._internals.setValidity({});
89
+ } else if (this.checked) {
90
+ this._internals.setFormValue(this.value);
91
+ this._internals.setValidity({});
92
+ } else {
93
+ this._internals.setFormValue(null);
94
+ this._internals.setValidity(this.validity, this.validationMessage, this.input);
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * The onChange function updates the checkbox state and emits an event for consumers.
101
+ * @param {Event} event - This should be the change event that was listened for on an input element with `type="checkbox"`.
102
+ */
41
103
  onChange (event: Event) {
42
104
  const { checked } = event?.currentTarget as HTMLInputElement;
43
- this.isChecked = checked;
105
+ this.checked = checked;
44
106
  const changedEvent = new CustomEvent(
45
107
  ON_SWITCH_CHANGED_EVENT,
46
108
  {
47
109
  bubbles: true,
48
110
  composed: true,
49
- detail: this.isChecked,
50
111
  },
51
112
  );
113
+
52
114
  this.dispatchEvent(changedEvent);
115
+ this.handleFormAssociation();
116
+ }
117
+
118
+ /**
119
+ * Returns a boolean value which indicates validity of the value of the component. If the value is invalid, this method also fires the invalid event on the component.
120
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checkValidity
121
+ * @returns boolean
122
+ */
123
+ public checkValidity (): boolean {
124
+ return (this.input as HTMLInputElement).checkValidity();
125
+ }
126
+
127
+ /**
128
+ * If the value is invalid, this method also fires the invalid event on the element, and (if the event isn't canceled) reports the problem to the user.
129
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/reportValidity
130
+ * @returns boolean
131
+ */
132
+ public reportValidity (): boolean {
133
+ return (this.input as HTMLInputElement).reportValidity();
134
+ }
135
+
136
+ /**
137
+ * Allows a consumer to set a custom validation message on the switch. An empty string counts as valid.
138
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setCustomValidity
139
+ */
140
+ public setCustomValidity (message: string): void {
141
+ this.input?.setCustomValidity(message);
142
+ this._internals.setValidity(this.validity, this.validationMessage, this.input);
143
+ }
144
+
145
+ /**
146
+ * (Read-only) returns a ValidityState with the validity states that this element is in.
147
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
148
+ */
149
+ public get validity (): ValidityState {
150
+ return (this.input as HTMLInputElement).validity;
151
+ }
152
+
153
+ /**
154
+ * (Read-only) Returns a string representing a localized message that describes the validation constraints that the control does not satisfy (if any).
155
+ * This string is empty if the component is valid.
156
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage
157
+ */
158
+ public get validationMessage (): string {
159
+ return (this.input as HTMLInputElement).validationMessage;
53
160
  }
54
161
 
55
162
  /**
@@ -77,7 +184,8 @@ export class PieSwitch extends RtlMixin(LitElement) implements SwitchProps {
77
184
  const {
78
185
  labelPlacement,
79
186
  aria,
80
- isChecked,
187
+ checked,
188
+ required,
81
189
  isDisabled,
82
190
  isRTL,
83
191
  } = this;
@@ -93,20 +201,21 @@ export class PieSwitch extends RtlMixin(LitElement) implements SwitchProps {
93
201
  <label
94
202
  data-test-id="switch-component"
95
203
  class="c-switch"
96
- ?isChecked=${isChecked}>
204
+ ?checked=${checked}>
97
205
  <input
98
206
  id="switch"
99
207
  data-test-id="switch-input"
100
208
  role="switch"
101
209
  type="checkbox"
102
210
  class="c-switch-input"
103
- .checked="${isChecked}"
211
+ .required=${required}
212
+ .checked="${checked}"
104
213
  .disabled="${isDisabled}"
105
214
  @change="${this.onChange}"
106
215
  aria-label="${aria?.label || nothing}"
107
216
  aria-describedby="${aria?.describedBy ? switchId : nothing}">
108
217
  <div class="c-switch-control">
109
- ${isChecked ? html`<icon-check></icon-check>` : nothing}
218
+ ${checked ? html`<icon-check></icon-check>` : nothing}
110
219
  </div>
111
220
  </label>
112
221
  ${aria?.describedBy ? html`<div id="${switchId}" data-test-id="${switchId}" class="c-switch-description">${aria?.describedBy}</div>` : nothing}
package/src/switch.scss CHANGED
@@ -60,7 +60,7 @@
60
60
  background-color: hsl(var(--dt-color-interactive-form-h), var(--dt-color-interactive-form-s), calc(var(--dt-color-interactive-form-l) - var(--dt-color-active-01)));
61
61
  }
62
62
 
63
- &[isChecked] {
63
+ &[checked] {
64
64
  @include switch-transition(background-color);
65
65
  background-color: var(--switch-bg-color--checked);
66
66
 
@@ -85,8 +85,17 @@
85
85
  }
86
86
 
87
87
  .c-switch-input {
88
- appearance: none;
89
- margin: 0;
88
+ position: absolute;
89
+ width: 1px;
90
+ height: 1px;
91
+ margin: -1px;
92
+ padding: 0;
93
+ overflow: hidden;
94
+ clip: rect(0, 0, 0, 0);
95
+ border: 0;
96
+ left: 50%;
97
+ transform: translateX(-50%) translateY(-50%);
98
+ bottom: 0;
90
99
 
91
100
  &:disabled {
92
101
  background-color: transparent;