@justeattakeaway/pie-select 0.6.11 → 0.7.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 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,33 +1,34 @@
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.0";
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, i = (t, e, o, r) => {
24
+ for (var s = r > 1 ? void 0 : r ? P(e, o) : e, a = t.length - 1, d; a >= 0; a--)
25
+ (d = t[a]) && (s = (r ? d(e, o, s) : d(s)) || s);
26
+ return r && s && F(e, o, 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
+ 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) => {
31
32
  const e = z(t);
32
33
  this.dispatchEvent(e), this._internals.setFormValue(this._select.value);
33
34
  };
@@ -35,6 +36,13 @@ let s = class extends I(w(g)) {
35
36
  firstUpdated() {
36
37
  this._internals.setFormValue(this._select.value);
37
38
  }
39
+ get value() {
40
+ return this._value === "" ? this._select ? this._select.value : "" : this._value;
41
+ }
42
+ set value(t) {
43
+ const e = t ? String(t) : "";
44
+ this._internals.setFormValue(e), this._value = e, this.requestUpdate();
45
+ }
38
46
  /**
39
47
  * (Read-only) returns a ValidityState with the validity states that this element is in.
40
48
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
@@ -56,8 +64,8 @@ let s = class extends I(w(g)) {
56
64
  * Resets the value to the default select value.
57
65
  */
58
66
  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);
67
+ 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 : "", o = t.find((s) => s.selected === !0), r = o ? o.value : e;
68
+ this._select.value = r || "", this._internals.setFormValue(r || null), this._value = r || "", this.requestUpdate();
61
69
  }
62
70
  _handleLeadingIconSlotchange() {
63
71
  this._hasLeadingIcon = !!this._leadingIconSlot.length;
@@ -69,21 +77,26 @@ let s = class extends I(w(g)) {
69
77
  */
70
78
  renderChildren(t) {
71
79
  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
- `)}
80
+ ${t.map((e) => {
81
+ if (e.tag === "optgroup")
82
+ return p`
83
+ <optgroup
84
+ ?disabled="${e.disabled}"
85
+ label="${u(e.label)}">
86
+ ${this.renderChildren(e.options)}
87
+ </optgroup>
88
+ `;
89
+ const r = this._value !== "" ? this._value === e.value : e.selected;
90
+ return p`
91
+ <option
92
+ .value="${L(e.value || "")}"
93
+ ?disabled="${e.disabled}"
94
+ ?selected="${r}">
95
+ ${e.text}
96
+ </option>
86
97
  `;
98
+ })}
99
+ `;
87
100
  }
88
101
  /**
89
102
  * Renders the assistive text if available.
@@ -92,8 +105,8 @@ let s = class extends I(w(g)) {
92
105
  renderAssistiveText() {
93
106
  return this.assistiveText ? p`
94
107
  <pie-assistive-text
95
- id="${u}"
96
- variant="${h(this.status)}"
108
+ id="${v}"
109
+ variant="${u(this.status)}"
97
110
  data-test-id="pie-select-assistive-text">
98
111
  ${this.assistiveText}
99
112
  </pie-assistive-text>
@@ -103,32 +116,32 @@ let s = class extends I(w(g)) {
103
116
  const {
104
117
  assistiveText: t,
105
118
  disabled: e,
106
- status: r,
107
- size: l,
108
- name: i,
109
- options: n,
119
+ status: o,
120
+ size: r,
121
+ name: s,
122
+ options: a,
110
123
  _hasLeadingIcon: d
111
124
  } = this, y = {
112
125
  "c-select": !0,
113
- [`c-select--${l}`]: !0,
114
126
  [`c-select--${r}`]: !0,
127
+ [`c-select--${o}`]: !0,
115
128
  "c-select--withLeadingIcon": d,
116
129
  "is-disabled": e
117
130
  };
118
131
  return p`
119
132
  <div
120
- class="${L(y)}"
133
+ class="${V(y)}"
121
134
  data-test-id="pie-select-shell">
122
135
  <slot name="leadingIcon" @slotchange=${this._handleLeadingIconSlotchange}></slot>
123
136
  <select
124
137
  data-test-id="pie-select-element"
125
- name="${h(i)}"
138
+ name="${u(s)}"
126
139
  ?disabled="${e}"
127
- aria-describedby="${h(t ? u : void 0)}"
128
- aria-invalid="${r === "error" ? "true" : "false"}"
129
- aria-errormessage="${h(r === "error" ? u : void 0)}"
140
+ aria-describedby="${u(t ? v : void 0)}"
141
+ aria-invalid="${o === "error" ? "true" : "false"}"
142
+ aria-errormessage="${u(o === "error" ? v : void 0)}"
130
143
  @change=${this._handleChange}>
131
- ${this.renderChildren(n)}
144
+ ${this.renderChildren(a)}
132
145
  </select>
133
146
  <icon-chevron-down size='s' class='c-select-trailingIcon'></icon-chevron-down>
134
147
  </div>
@@ -136,46 +149,49 @@ let s = class extends I(w(g)) {
136
149
  `;
137
150
  }
138
151
  };
139
- s.shadowRootOptions = { ...b.shadowRootOptions, delegatesFocus: !0 };
140
- s.styles = $(A);
141
- o([
142
- c({ type: String }),
143
- f(x, O, a.size)
144
- ], s.prototype, "size", 2);
145
- o([
146
- c({ type: Boolean })
147
- ], s.prototype, "disabled", 2);
148
- o([
149
- c({ type: String }),
150
- f(x, F, a.status)
151
- ], s.prototype, "status", 2);
152
- o([
153
- c({ type: String })
154
- ], s.prototype, "assistiveText", 2);
155
- o([
156
- c({ type: String, reflect: !0 })
157
- ], s.prototype, "name", 2);
158
- o([
159
- c({ type: Array })
160
- ], s.prototype, "options", 2);
161
- o([
152
+ l.shadowRootOptions = { ...b.shadowRootOptions, delegatesFocus: !0 };
153
+ l.styles = $(T);
154
+ i([
155
+ n({ type: String }),
156
+ f(x, O, c.size)
157
+ ], l.prototype, "size", 2);
158
+ i([
159
+ n({ type: Boolean })
160
+ ], l.prototype, "disabled", 2);
161
+ i([
162
+ n({ type: String }),
163
+ f(x, A, c.status)
164
+ ], l.prototype, "status", 2);
165
+ i([
166
+ n({ type: String })
167
+ ], l.prototype, "assistiveText", 2);
168
+ i([
169
+ n({ type: String, reflect: !0 })
170
+ ], l.prototype, "name", 2);
171
+ i([
172
+ n({ type: Array })
173
+ ], l.prototype, "options", 2);
174
+ i([
162
175
  m("select")
163
- ], s.prototype, "focusTarget", 2);
164
- o([
176
+ ], l.prototype, "focusTarget", 2);
177
+ i([
165
178
  m("select")
166
- ], s.prototype, "_select", 2);
167
- o([
179
+ ], l.prototype, "_select", 2);
180
+ i([
168
181
  S({ slot: "leadingIcon", flatten: !0 })
169
- ], s.prototype, "_leadingIconSlot", 2);
170
- o([
182
+ ], l.prototype, "_leadingIconSlot", 2);
183
+ i([
171
184
  C()
172
- ], s.prototype, "_hasLeadingIcon", 2);
173
- s = o([
185
+ ], l.prototype, "_hasLeadingIcon", 2);
186
+ i([
187
+ n()
188
+ ], l.prototype, "value", 1);
189
+ l = i([
174
190
  k("pie-select")
175
- ], s);
191
+ ], l);
176
192
  export {
177
- s as PieSelect,
178
- a as defaultProps,
193
+ l as PieSelect,
194
+ c as defaultProps,
179
195
  O as sizes,
180
- F as statusTypes
196
+ A as statusTypes
181
197
  };
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.0",
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
  /**
@@ -139,27 +181,30 @@ export class PieSelect extends FormControlMixin(RtlMixin(PieElement)) implements
139
181
  */
140
182
  private renderChildren (options: SelectProps['options']): TemplateResult {
141
183
  return html`
142
- ${options.map((option) => {
184
+ ${options.map((option) => {
143
185
  if (option.tag === 'optgroup') {
144
186
  return html`
145
- <optgroup
146
- ?disabled="${option.disabled}"
147
- label="${ifDefined(option.label)}">
148
- ${this.renderChildren(option.options)}
149
- </optgroup>
150
- `;
187
+ <optgroup
188
+ ?disabled="${option.disabled}"
189
+ label="${ifDefined(option.label)}">
190
+ ${this.renderChildren(option.options)}
191
+ </optgroup>
192
+ `;
151
193
  }
152
194
 
195
+ const hasValue = this._value !== '';
196
+ const selected = hasValue ? this._value === option.value : option.selected;
197
+
153
198
  return html`
154
- <option
155
- .value="${live(option.value)}"
156
- ?disabled="${option.disabled}"
157
- ?selected="${option.selected}">
158
- ${option.text}
159
- </option>
160
- `;
161
- })}
199
+ <option
200
+ .value="${live(option.value || '')}"
201
+ ?disabled="${option.disabled}"
202
+ ?selected="${selected}">
203
+ ${option.text}
204
+ </option>
162
205
  `;
206
+ })}
207
+ `;
163
208
  }
164
209
 
165
210
  /**