@justeattakeaway/pie-select 0.6.11 → 0.7.1

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 CHANGED
@@ -34,10 +34,11 @@ Ideally, you should install the component using the **`@justeattakeaway/pie-webc
34
34
  |----------------|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
35
35
  | `size` | `"small"`, `"medium"`, `"large"` | The size of the select component. | `medium` |
36
36
  | `disabled` | `boolean` | Whether the select is disabled. | `false` |
37
- | `assistiveText`| `string` | An optional assistive text to display below the select element. Must be provided when the status is `error`. | `undefined` |
37
+ | `assistiveText`| `string` | An optional assistive text to display below the select element. Must be provided when the status is `error`. | `undefined` |
38
38
  | `status` | `"default"`, `"error"` | The status of the select component / assistive text. | `default` |
39
- | `name` | `string` | The name of the select (used as a key/value pair with `value`). This is required in order to work properly with forms. | `undefined` |
40
- | `options` | `array` | The options to display in the select. Can be an array of option objects or option group objects. See [Using the options prop](#using-the-options-prop) for more details. | `[]` |
39
+ | `name` | `string` | The name of the select (used as a key/value pair with `value`). This is required in order to work properly with forms. | `undefined` |
40
+ | `options` | `array` | The options to display in the select. Can be an array of option objects or option group objects. See [Using the options prop](#using-the-options-prop) for more details. | `[]` |
41
+ | `value` | `string` | The programatically set value of the select. It overrides any option set as selected. | `` |
41
42
 
42
43
  #### Using the options prop
43
44
  The `options` prop accepts an array of option objects or option group objects:
@@ -88,14 +89,21 @@ import '@justeattakeaway/pie-icons-webc/dist/IconPlaceholder.js';
88
89
  ```html
89
90
  <pie-select
90
91
  name="my-select"
91
- options="[
92
- { tag: 'option', text: 'Select an option' },
93
- { tag: 'option', text: 'Option 1', value: 'option1' }
94
- ]">
92
+ value="option2">
95
93
  <icon-placeholder slot="leadingIcon"></icon-placeholder>
96
94
  </pie-select>
97
95
  ```
98
96
 
97
+ ```js
98
+ // Set options programmatically
99
+ const select = document.querySelector('pie-select');
100
+ select.options = [
101
+ { tag: 'option', text: 'Select an option' },
102
+ { tag: 'option', text: 'Option 1', value: 'option1' },
103
+ { tag: 'option', text: 'Option 2', value: 'option2' }
104
+ ];
105
+ ```
106
+
99
107
  **For Native JS Applications, Vue, Angular, Svelte, etc.:**
100
108
 
101
109
  ```js
@@ -105,9 +113,11 @@ import '@justeattakeaway/pie-icons-webc/dist/IconPlaceholder.js';
105
113
 
106
114
  <pie-select
107
115
  name="my-select"
116
+ value="option2"
108
117
  :options="[
109
118
  { tag: 'option', text: 'Select an option' },
110
119
  { tag: 'option', text: 'Option 1', value: 'option1' }
120
+ { tag: 'option', text: 'Option 2', value: 'option2' }
111
121
  ]">
112
122
  <icon-placeholder slot="leadingIcon"></icon-placeholder>
113
123
  </pie-select>
@@ -120,9 +130,11 @@ import { IconPlaceholder } from '@justeattakeaway/pie-icons-webc/dist/react/Icon
120
130
 
121
131
  <PieSelect
122
132
  name="my-select"
133
+ value="option2"
123
134
  options={[
124
135
  { tag: 'option', text: 'Select an option' },
125
- { tag: 'option', text: 'Option 1', value: 'option1' }
136
+ { tag: 'option', text: 'Option 1', value: 'option1' },
137
+ { tag: 'option', text: 'Option 2', value: 'option2' },
126
138
  ]}>
127
139
  <IconPlaceholder slot="leadingIcon"></IconPlaceholder>
128
140
  </PieSelect>
@@ -34,7 +34,7 @@
34
34
  "type": {
35
35
  "text": "DefaultProps"
36
36
  },
37
- "default": "{\n size: 'medium',\n status: 'default',\n disabled: false,\n options: [],\n}"
37
+ "default": "{\n size: 'medium',\n status: 'default',\n disabled: false,\n options: [],\n value: '',\n}"
38
38
  }
39
39
  ],
40
40
  "exports": [
@@ -121,6 +121,14 @@
121
121
  },
122
122
  "privacy": "public"
123
123
  },
124
+ {
125
+ "kind": "field",
126
+ "name": "_value",
127
+ "type": {
128
+ "text": "SelectProps['value']"
129
+ },
130
+ "privacy": "private"
131
+ },
124
132
  {
125
133
  "kind": "field",
126
134
  "name": "focusTarget",
@@ -154,6 +162,14 @@
154
162
  "privacy": "private",
155
163
  "default": "false"
156
164
  },
165
+ {
166
+ "kind": "field",
167
+ "name": "value",
168
+ "type": {
169
+ "text": "SelectProps['value']"
170
+ },
171
+ "privacy": "public"
172
+ },
157
173
  {
158
174
  "kind": "field",
159
175
  "name": "validity",
package/dist/index.d.ts CHANGED
@@ -27,11 +27,14 @@ export declare class PieSelect extends PieSelect_base implements SelectProps {
27
27
  assistiveText: SelectProps['assistiveText'];
28
28
  name: SelectProps['name'];
29
29
  options: SelectProps['options'];
30
+ private _value;
30
31
  focusTarget: HTMLSelectElement;
31
32
  private _select;
32
33
  private _leadingIconSlot;
33
34
  private _hasLeadingIcon;
34
35
  protected firstUpdated(): void;
36
+ get value(): SelectProps['value'];
37
+ set value(newValue: SelectProps['value']);
35
38
  /**
36
39
  * (Read-only) returns a ValidityState with the validity states that this element is in.
37
40
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
@@ -72,7 +75,7 @@ export declare class PieSelect extends PieSelect_base implements SelectProps {
72
75
 
73
76
  declare const PieSelect_base: GenericConstructor<FormControlInterface> & GenericConstructor<RTLInterface> & typeof PieElement;
74
77
 
75
- declare interface SelectOptionGroupProps {
78
+ export declare interface SelectOptionGroupProps {
76
79
  /**
77
80
  * What HTML element the option should be such option or optgroup.
78
81
  */
@@ -91,7 +94,7 @@ declare interface SelectOptionGroupProps {
91
94
  disabled?: boolean;
92
95
  }
93
96
 
94
- declare interface SelectOptionProps {
97
+ export declare interface SelectOptionProps {
95
98
  /**
96
99
  * What HTML element the option should be such option or optgroup.
97
100
  */
@@ -139,6 +142,10 @@ export declare interface SelectProps {
139
142
  * The options to display in the select. Can be an array of option objects or option group objects.
140
143
  */
141
144
  options: (SelectOptionProps | SelectOptionGroupProps)[];
145
+ /**
146
+ * The value of the selected option
147
+ */
148
+ value?: string | number;
142
149
  }
143
150
 
144
151
  export declare const sizes: readonly ["small", "medium", "large"];
package/dist/index.js CHANGED
@@ -1,40 +1,50 @@
1
1
  import { LitElement as b, html as p, nothing as _, unsafeCSS as $ } from "lit";
2
2
  import { FormControlMixin as I, RtlMixin as w, wrapNativeEvent as z, validPropertyValues as f, safeCustomElement as k } from "@justeattakeaway/pie-webc-core";
3
- import { property as c, query as m, queryAssignedElements as S, state as C } from "lit/decorators.js";
4
- import { ifDefined as h } from "lit/directives/if-defined.js";
5
- import { classMap as L } from "lit/directives/class-map.js";
6
- import { live as T } from "lit/directives/live.js";
3
+ import { property as n, query as m, queryAssignedElements as S, state as C } from "lit/decorators.js";
4
+ import { ifDefined as u } from "lit/directives/if-defined.js";
5
+ import { classMap as V } from "lit/directives/class-map.js";
6
+ import { live as L } from "lit/directives/live.js";
7
7
  import "@justeattakeaway/pie-icons-webc/dist/IconChevronDown.js";
8
8
  import "@justeattakeaway/pie-assistive-text";
9
- const v = class v extends b {
9
+ const h = class h extends b {
10
10
  willUpdate() {
11
- this.getAttribute("v") || this.setAttribute("v", v.v);
11
+ this.getAttribute("v") || this.setAttribute("v", h.v);
12
12
  }
13
13
  };
14
- v.v = "0.6.11";
15
- let g = v;
16
- const A = "*,*:after,*:before{box-sizing:inherit}:host{display:block}.c-select{--select-padding-block: var(--dt-spacing-c);--select-padding-inline-start: var(--dt-spacing-d);--select-padding-inline-end: 52px;--select-background-color: var(--dt-color-container-default);--select-text-color: var(--dt-color-content-default);--select-border-color: var(--dt-color-border-form);--select-font-size: calc(var(--dt-font-body-l-size) * 1px);--select-line-height: calc(var(--dt-font-body-l-line-height) * 1px);--select-height: 48px;--select-cursor: pointer;position:relative;color:var(--select-text-color);font-size:var(--select-font-size);line-height:var(--select-line-height)}.c-select select{height:var(--select-height);width:100%;border:1px solid var(--select-border-color);border-radius:var(--dt-radius-rounded-c);padding-inline-start:var(--select-padding-inline-start);padding-inline-end:var(--select-padding-inline-end);padding-block-start:var(--select-padding-block);padding-block-end:var(--select-padding-block);background-color:var(--select-background-color);font-family:inherit;font-size:inherit;line-height:inherit;color:inherit;outline:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:var(--select-cursor);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.c-select select:focus-within{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.c-select.c-select--small{--select-padding-block: var(--dt-spacing-b);--select-height: 40px}.c-select.c-select--large{--select-padding-block: var(--dt-spacing-d);--select-height: 56px}.c-select.c-select--error{--select-border-color: var(--dt-color-support-error)}.c-select.c-select--withLeadingIcon{--select-padding-inline-start: calc(var(--dt-spacing-h) - var(--dt-spacing-a))}.c-select ::slotted([slot=leadingIcon]),.c-select .c-select-trailingIcon{position:absolute;top:50%;transform:translateY(-50%);pointer-events:none}.c-select:not(.is-disabled) ::slotted([slot=leadingIcon]),.c-select:not(.is-disabled) .c-select-trailingIcon{color:var(--dt-color-content-subdued)}.c-select ::slotted([slot=leadingIcon]){--icon-display-override: block;--icon-size-override: 24px;inset-inline-start:var(--dt-spacing-d)}.c-select .c-select-trailingIcon{inset-inline-end:var(--dt-spacing-d)}@media (hover: hover){.c-select:hover{--select-background-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + calc(-1 * var(--dt-color-hover-01))))}@supports (background-color: color-mix(in srgb,black,white)){.c-select:hover{--select-background-color: color-mix(in srgb, var(--dt-color-hover-01-bg) var(--dt-color-hover-01), var(--dt-color-container-default))}}}.c-select.is-disabled{--select-background-color: var(--dt-color-disabled-01);--select-border-color: var(--dt-color-disabled-01);--select-text-color: var(--dt-color-content-disabled);--select-cursor: auto}", O = ["small", "medium", "large"], F = ["default", "error"], a = {
14
+ h.v = "0.7.1";
15
+ let g = h;
16
+ const T = "*,*:after,*:before{box-sizing:inherit}:host{display:block}.c-select{--select-padding-block: var(--dt-spacing-c);--select-padding-inline-start: var(--dt-spacing-d);--select-padding-inline-end: 52px;--select-background-color: var(--dt-color-container-default);--select-text-color: var(--dt-color-content-default);--select-border-color: var(--dt-color-border-form);--select-font-size: calc(var(--dt-font-body-l-size) * 1px);--select-line-height: calc(var(--dt-font-body-l-line-height) * 1px);--select-height: 48px;--select-cursor: pointer;position:relative;color:var(--select-text-color);font-size:var(--select-font-size);line-height:var(--select-line-height)}.c-select select{height:var(--select-height);width:100%;border:1px solid var(--select-border-color);border-radius:var(--dt-radius-rounded-c);padding-inline-start:var(--select-padding-inline-start);padding-inline-end:var(--select-padding-inline-end);padding-block-start:var(--select-padding-block);padding-block-end:var(--select-padding-block);background-color:var(--select-background-color);font-family:inherit;font-size:inherit;line-height:inherit;color:inherit;outline:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:var(--select-cursor);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.c-select select:focus-within{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.c-select.c-select--small{--select-padding-block: var(--dt-spacing-b);--select-height: 40px}.c-select.c-select--large{--select-padding-block: var(--dt-spacing-d);--select-height: 56px}.c-select.c-select--error{--select-border-color: var(--dt-color-support-error)}.c-select.c-select--withLeadingIcon{--select-padding-inline-start: calc(var(--dt-spacing-h) - var(--dt-spacing-a))}.c-select ::slotted([slot=leadingIcon]),.c-select .c-select-trailingIcon{position:absolute;top:50%;transform:translateY(-50%);pointer-events:none}.c-select:not(.is-disabled) ::slotted([slot=leadingIcon]),.c-select:not(.is-disabled) .c-select-trailingIcon{color:var(--dt-color-content-subdued)}.c-select ::slotted([slot=leadingIcon]){--icon-display-override: block;--icon-size-override: 24px;inset-inline-start:var(--dt-spacing-d)}.c-select .c-select-trailingIcon{inset-inline-end:var(--dt-spacing-d)}@media (hover: hover){.c-select:hover{--select-background-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + calc(-1 * var(--dt-color-hover-01))))}@supports (background-color: color-mix(in srgb,black,white)){.c-select:hover{--select-background-color: color-mix(in srgb, var(--dt-color-hover-01-bg) var(--dt-color-hover-01), var(--dt-color-container-default))}}}.c-select.is-disabled{--select-background-color: var(--dt-color-disabled-01);--select-border-color: var(--dt-color-disabled-01);--select-text-color: var(--dt-color-content-disabled);--select-cursor: auto}", O = ["small", "medium", "large"], A = ["default", "error"], c = {
17
17
  size: "medium",
18
18
  status: "default",
19
19
  disabled: !1,
20
- options: []
20
+ options: [],
21
+ value: ""
21
22
  };
22
- var P = Object.defineProperty, V = Object.getOwnPropertyDescriptor, o = (t, e, r, l) => {
23
- for (var i = l > 1 ? void 0 : l ? V(e, r) : e, n = t.length - 1, d; n >= 0; n--)
24
- (d = t[n]) && (i = (l ? d(e, r, i) : d(i)) || i);
25
- return l && i && P(e, r, i), i;
23
+ var F = Object.defineProperty, P = Object.getOwnPropertyDescriptor, o = (t, e, r, i) => {
24
+ for (var s = i > 1 ? void 0 : i ? P(e, r) : e, a = t.length - 1, d; a >= 0; a--)
25
+ (d = t[a]) && (s = (i ? d(e, r, s) : d(s)) || s);
26
+ return i && s && F(e, r, s), s;
26
27
  };
27
- const x = "pie-select", u = "assistive-text";
28
- let s = class extends I(w(g)) {
28
+ const x = "pie-select", v = "assistive-text";
29
+ let l = class extends I(w(g)) {
29
30
  constructor() {
30
- super(...arguments), this.size = a.size, this.disabled = a.disabled, this.status = a.status, this.options = a.options, this._hasLeadingIcon = !1, this._handleChange = (t) => {
31
- const e = z(t);
32
- this.dispatchEvent(e), this._internals.setFormValue(this._select.value);
31
+ super(...arguments), this.size = c.size, this.disabled = c.disabled, this.status = c.status, this.options = c.options, this._value = c.value, this._hasLeadingIcon = !1, this._handleChange = (t) => {
32
+ const { value: e } = this._select;
33
+ this._value = e, this._internals.setFormValue(e);
34
+ const r = z(t);
35
+ this.dispatchEvent(r);
33
36
  };
34
37
  }
35
38
  firstUpdated() {
36
39
  this._internals.setFormValue(this._select.value);
37
40
  }
41
+ get value() {
42
+ return this._value === "" ? this._select ? this._select.value : "" : this._value;
43
+ }
44
+ set value(t) {
45
+ const e = t ? String(t) : "";
46
+ this._internals.setFormValue(e), this._value = e, this.requestUpdate();
47
+ }
38
48
  /**
39
49
  * (Read-only) returns a ValidityState with the validity states that this element is in.
40
50
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
@@ -56,8 +66,8 @@ let s = class extends I(w(g)) {
56
66
  * Resets the value to the default select value.
57
67
  */
58
68
  formResetCallback() {
59
- const t = this._select.querySelector("option[selected]");
60
- this._select.value = (t == null ? void 0 : t.getAttribute("value")) ?? "", this._select.selectedIndex = t ? this._select.selectedIndex : 0, this._internals.setFormValue(this._select.value);
69
+ const t = this.options.reduce((s, a) => a.tag === "optgroup" ? s.concat(a.options) : (s.push(a), s), []), e = t.length > 0 ? t[0].value : "", r = t.find((s) => s.selected === !0), i = r ? r.value : e;
70
+ this._select.value = i || "", this._internals.setFormValue(i || null), this._value = i || "", this.requestUpdate();
61
71
  }
62
72
  _handleLeadingIconSlotchange() {
63
73
  this._hasLeadingIcon = !!this._leadingIconSlot.length;
@@ -69,21 +79,26 @@ let s = class extends I(w(g)) {
69
79
  */
70
80
  renderChildren(t) {
71
81
  return p`
72
- ${t.map((e) => e.tag === "optgroup" ? p`
73
- <optgroup
74
- ?disabled="${e.disabled}"
75
- label="${h(e.label)}">
76
- ${this.renderChildren(e.options)}
77
- </optgroup>
78
- ` : p`
79
- <option
80
- .value="${T(e.value)}"
81
- ?disabled="${e.disabled}"
82
- ?selected="${e.selected}">
83
- ${e.text}
84
- </option>
85
- `)}
82
+ ${t.map((e) => {
83
+ if (e.tag === "optgroup")
84
+ return p`
85
+ <optgroup
86
+ ?disabled="${e.disabled}"
87
+ label="${u(e.label)}">
88
+ ${this.renderChildren(e.options)}
89
+ </optgroup>
90
+ `;
91
+ const i = this._value !== "" ? this._value === e.value : e.selected;
92
+ return p`
93
+ <option
94
+ .value="${L(e.value || "")}"
95
+ ?disabled="${e.disabled}"
96
+ ?selected="${i}">
97
+ ${e.text}
98
+ </option>
86
99
  `;
100
+ })}
101
+ `;
87
102
  }
88
103
  /**
89
104
  * Renders the assistive text if available.
@@ -92,8 +107,8 @@ let s = class extends I(w(g)) {
92
107
  renderAssistiveText() {
93
108
  return this.assistiveText ? p`
94
109
  <pie-assistive-text
95
- id="${u}"
96
- variant="${h(this.status)}"
110
+ id="${v}"
111
+ variant="${u(this.status)}"
97
112
  data-test-id="pie-select-assistive-text">
98
113
  ${this.assistiveText}
99
114
  </pie-assistive-text>
@@ -104,31 +119,31 @@ let s = class extends I(w(g)) {
104
119
  assistiveText: t,
105
120
  disabled: e,
106
121
  status: r,
107
- size: l,
108
- name: i,
109
- options: n,
122
+ size: i,
123
+ name: s,
124
+ options: a,
110
125
  _hasLeadingIcon: d
111
126
  } = this, y = {
112
127
  "c-select": !0,
113
- [`c-select--${l}`]: !0,
128
+ [`c-select--${i}`]: !0,
114
129
  [`c-select--${r}`]: !0,
115
130
  "c-select--withLeadingIcon": d,
116
131
  "is-disabled": e
117
132
  };
118
133
  return p`
119
134
  <div
120
- class="${L(y)}"
135
+ class="${V(y)}"
121
136
  data-test-id="pie-select-shell">
122
137
  <slot name="leadingIcon" @slotchange=${this._handleLeadingIconSlotchange}></slot>
123
138
  <select
124
139
  data-test-id="pie-select-element"
125
- name="${h(i)}"
140
+ name="${u(s)}"
126
141
  ?disabled="${e}"
127
- aria-describedby="${h(t ? u : void 0)}"
142
+ aria-describedby="${u(t ? v : void 0)}"
128
143
  aria-invalid="${r === "error" ? "true" : "false"}"
129
- aria-errormessage="${h(r === "error" ? u : void 0)}"
144
+ aria-errormessage="${u(r === "error" ? v : void 0)}"
130
145
  @change=${this._handleChange}>
131
- ${this.renderChildren(n)}
146
+ ${this.renderChildren(a)}
132
147
  </select>
133
148
  <icon-chevron-down size='s' class='c-select-trailingIcon'></icon-chevron-down>
134
149
  </div>
@@ -136,46 +151,49 @@ let s = class extends I(w(g)) {
136
151
  `;
137
152
  }
138
153
  };
139
- s.shadowRootOptions = { ...b.shadowRootOptions, delegatesFocus: !0 };
140
- s.styles = $(A);
154
+ l.shadowRootOptions = { ...b.shadowRootOptions, delegatesFocus: !0 };
155
+ l.styles = $(T);
141
156
  o([
142
- c({ type: String }),
143
- f(x, O, a.size)
144
- ], s.prototype, "size", 2);
157
+ n({ type: String }),
158
+ f(x, O, c.size)
159
+ ], l.prototype, "size", 2);
145
160
  o([
146
- c({ type: Boolean })
147
- ], s.prototype, "disabled", 2);
161
+ n({ type: Boolean })
162
+ ], l.prototype, "disabled", 2);
148
163
  o([
149
- c({ type: String }),
150
- f(x, F, a.status)
151
- ], s.prototype, "status", 2);
164
+ n({ type: String }),
165
+ f(x, A, c.status)
166
+ ], l.prototype, "status", 2);
152
167
  o([
153
- c({ type: String })
154
- ], s.prototype, "assistiveText", 2);
168
+ n({ type: String })
169
+ ], l.prototype, "assistiveText", 2);
155
170
  o([
156
- c({ type: String, reflect: !0 })
157
- ], s.prototype, "name", 2);
171
+ n({ type: String, reflect: !0 })
172
+ ], l.prototype, "name", 2);
158
173
  o([
159
- c({ type: Array })
160
- ], s.prototype, "options", 2);
174
+ n({ type: Array })
175
+ ], l.prototype, "options", 2);
161
176
  o([
162
177
  m("select")
163
- ], s.prototype, "focusTarget", 2);
178
+ ], l.prototype, "focusTarget", 2);
164
179
  o([
165
180
  m("select")
166
- ], s.prototype, "_select", 2);
181
+ ], l.prototype, "_select", 2);
167
182
  o([
168
183
  S({ slot: "leadingIcon", flatten: !0 })
169
- ], s.prototype, "_leadingIconSlot", 2);
184
+ ], l.prototype, "_leadingIconSlot", 2);
170
185
  o([
171
186
  C()
172
- ], s.prototype, "_hasLeadingIcon", 2);
173
- s = o([
187
+ ], l.prototype, "_hasLeadingIcon", 2);
188
+ o([
189
+ n()
190
+ ], l.prototype, "value", 1);
191
+ l = o([
174
192
  k("pie-select")
175
- ], s);
193
+ ], l);
176
194
  export {
177
- s as PieSelect,
178
- a as defaultProps,
195
+ l as PieSelect,
196
+ c as defaultProps,
179
197
  O as sizes,
180
- F as statusTypes
198
+ A as statusTypes
181
199
  };
package/dist/react.d.ts CHANGED
@@ -30,11 +30,14 @@ declare class PieSelect_2 extends PieSelect_base implements SelectProps {
30
30
  assistiveText: SelectProps['assistiveText'];
31
31
  name: SelectProps['name'];
32
32
  options: SelectProps['options'];
33
+ private _value;
33
34
  focusTarget: HTMLSelectElement;
34
35
  private _select;
35
36
  private _leadingIconSlot;
36
37
  private _hasLeadingIcon;
37
38
  protected firstUpdated(): void;
39
+ get value(): SelectProps['value'];
40
+ set value(newValue: SelectProps['value']);
38
41
  /**
39
42
  * (Read-only) returns a ValidityState with the validity states that this element is in.
40
43
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
@@ -81,7 +84,7 @@ declare type PieSelectEvents = {
81
84
 
82
85
  declare type ReactBaseType = Omit<React_2.HTMLAttributes<HTMLSelectElement>, 'onChange'>;
83
86
 
84
- declare interface SelectOptionGroupProps {
87
+ export declare interface SelectOptionGroupProps {
85
88
  /**
86
89
  * What HTML element the option should be such option or optgroup.
87
90
  */
@@ -100,7 +103,7 @@ declare interface SelectOptionGroupProps {
100
103
  disabled?: boolean;
101
104
  }
102
105
 
103
- declare interface SelectOptionProps {
106
+ export declare interface SelectOptionProps {
104
107
  /**
105
108
  * What HTML element the option should be such option or optgroup.
106
109
  */
@@ -148,6 +151,10 @@ export declare interface SelectProps {
148
151
  * The options to display in the select. Can be an array of option objects or option group objects.
149
152
  */
150
153
  options: (SelectOptionProps | SelectOptionGroupProps)[];
154
+ /**
155
+ * The value of the selected option
156
+ */
157
+ value?: string | number;
151
158
  }
152
159
 
153
160
  export declare const sizes: readonly ["small", "medium", "large"];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-select",
3
3
  "description": "PIE Design System Select built using Web Components",
4
- "version": "0.6.11",
4
+ "version": "0.7.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/justeattakeaway/pie",
@@ -40,7 +40,7 @@
40
40
  "devDependencies": {
41
41
  "@custom-elements-manifest/analyzer": "0.9.0",
42
42
  "@justeattakeaway/pie-components-config": "0.21.0",
43
- "@justeattakeaway/pie-css": "0.19.0",
43
+ "@justeattakeaway/pie-css": "0.21.0",
44
44
  "@justeattakeaway/pie-monorepo-utils": "0.7.0",
45
45
  "cem-plugin-module-file-extensions": "0.0.5"
46
46
  },
package/src/defs.ts CHANGED
@@ -4,7 +4,7 @@ export const sizes = ['small', 'medium', 'large'] as const;
4
4
 
5
5
  export const statusTypes = ['default', 'error'] as const;
6
6
 
7
- interface SelectOptionProps {
7
+ export interface SelectOptionProps {
8
8
  /**
9
9
  * What HTML element the option should be such option or optgroup.
10
10
  */
@@ -31,7 +31,7 @@ interface SelectOptionProps {
31
31
  selected?: boolean;
32
32
  }
33
33
 
34
- interface SelectOptionGroupProps {
34
+ export interface SelectOptionGroupProps {
35
35
  /**
36
36
  * What HTML element the option should be such option or optgroup.
37
37
  */
@@ -83,6 +83,11 @@ export interface SelectProps {
83
83
  * The options to display in the select. Can be an array of option objects or option group objects.
84
84
  */
85
85
  options: (SelectOptionProps | SelectOptionGroupProps)[];
86
+
87
+ /**
88
+ * The value of the selected option
89
+ */
90
+ value?: string | number;
86
91
  }
87
92
 
88
93
  type DefaultProps = ComponentDefaultProps<SelectProps, keyof Omit<SelectProps, 'name' | 'assistiveText'>>;
@@ -92,4 +97,5 @@ export const defaultProps: DefaultProps = {
92
97
  status: 'default',
93
98
  disabled: false,
94
99
  options: [],
100
+ value: '',
95
101
  };
package/src/index.ts CHANGED
@@ -31,6 +31,7 @@ import {
31
31
  sizes,
32
32
  statusTypes,
33
33
  type SelectProps,
34
+ type SelectOptionProps,
34
35
  } from './defs';
35
36
 
36
37
  // Valid values available to consumers
@@ -67,6 +68,8 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
67
68
  @property({ type: Array })
68
69
  public options: SelectProps['options'] = defaultProps.options;
69
70
 
71
+ private _value: SelectProps['value'] = defaultProps.value;
72
+
70
73
  @query('select')
71
74
  public focusTarget!: HTMLSelectElement;
72
75
 
@@ -83,6 +86,29 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
83
86
  this._internals.setFormValue(this._select.value);
84
87
  }
85
88
 
89
+ @property()
90
+ public get value (): SelectProps['value'] {
91
+ // If no value was assigned
92
+ // and the select element is available
93
+ // return its value as by default it will pick the first available option
94
+ if (this._value === '') {
95
+ if (!this._select) {
96
+ return '';
97
+ }
98
+ return this._select.value;
99
+ }
100
+
101
+ return this._value;
102
+ }
103
+
104
+ public set value (newValue: SelectProps['value']) {
105
+ const safeNewValue = newValue ? String(newValue) : '';
106
+ this._internals.setFormValue(safeNewValue);
107
+ this._value = safeNewValue;
108
+
109
+ this.requestUpdate();
110
+ }
111
+
86
112
  /**
87
113
  * (Read-only) returns a ValidityState with the validity states that this element is in.
88
114
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
@@ -106,10 +132,26 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
106
132
  * Resets the value to the default select value.
107
133
  */
108
134
  public formResetCallback (): void {
109
- const selected = this._select.querySelector('option[selected]');
110
- this._select.value = selected?.getAttribute('value') ?? '';
111
- this._select.selectedIndex = selected ? this._select.selectedIndex : 0;
112
- this._internals.setFormValue(this._select.value);
135
+ // Flatten a possibly nested options list into a flat one
136
+ const flatOptions: SelectOptionProps[] = this.options.reduce<SelectOptionProps[]>((acc, option) => {
137
+ if (option.tag === 'optgroup') {
138
+ return acc.concat(option.options);
139
+ }
140
+ acc.push(option);
141
+ return acc;
142
+ }, []);
143
+
144
+ // Infer the value to reset to
145
+ const firstValue = flatOptions.length > 0 ? flatOptions[0].value : '';
146
+ const selectedValue = flatOptions.find((option) => option.selected === true);
147
+ const resetValue = selectedValue ? selectedValue.value : firstValue;
148
+
149
+ // Perform the necessary updates
150
+ // _select, _internals, and _value must be synchronized to the same value
151
+ this._select.value = resetValue || '';
152
+ this._internals.setFormValue(resetValue || null);
153
+ this._value = resetValue || '';
154
+ this.requestUpdate();
113
155
  }
114
156
 
115
157
  /**
@@ -117,6 +159,11 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
117
159
  * @param event - The change event.
118
160
  */
119
161
  private _handleChange = (event: Event) => {
162
+ // Update value state
163
+ const { value } = this._select;
164
+ this._value = value;
165
+ this._internals.setFormValue(value);
166
+
120
167
  // We have to create our own change event because the native one
121
168
  // does not penetrate the shadow boundary.
122
169
 
@@ -124,8 +171,6 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
124
171
  // Reference: https://javascript.info/shadow-dom-events#event-composed
125
172
  const customChangeEvent = wrapNativeEvent(event);
126
173
  this.dispatchEvent(customChangeEvent);
127
-
128
- this._internals.setFormValue(this._select.value);
129
174
  };
130
175
 
131
176
  private _handleLeadingIconSlotchange () {
@@ -139,27 +184,30 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
139
184
  */
140
185
  private renderChildren (options: SelectProps['options']): TemplateResult {
141
186
  return html`
142
- ${options.map((option) => {
187
+ ${options.map((option) => {
143
188
  if (option.tag === 'optgroup') {
144
189
  return html`
145
- <optgroup
146
- ?disabled="${option.disabled}"
147
- label="${ifDefined(option.label)}">
148
- ${this.renderChildren(option.options)}
149
- </optgroup>
150
- `;
190
+ <optgroup
191
+ ?disabled="${option.disabled}"
192
+ label="${ifDefined(option.label)}">
193
+ ${this.renderChildren(option.options)}
194
+ </optgroup>
195
+ `;
151
196
  }
152
197
 
198
+ const hasValue = this._value !== '';
199
+ const selected = hasValue ? this._value === option.value : option.selected;
200
+
153
201
  return html`
154
- <option
155
- .value="${live(option.value)}"
156
- ?disabled="${option.disabled}"
157
- ?selected="${option.selected}">
158
- ${option.text}
159
- </option>
160
- `;
161
- })}
202
+ <option
203
+ .value="${live(option.value || '')}"
204
+ ?disabled="${option.disabled}"
205
+ ?selected="${selected}">
206
+ ${option.text}
207
+ </option>
162
208
  `;
209
+ })}
210
+ `;
163
211
  }
164
212
 
165
213
  /**