@justeattakeaway/pie-select 0.2.0 → 0.3.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/src/index.ts CHANGED
@@ -3,11 +3,14 @@ import {
3
3
  html,
4
4
  nothing,
5
5
  unsafeCSS,
6
+ type TemplateResult,
6
7
  } from 'lit';
7
8
  import {
9
+ FormControlMixin,
8
10
  RtlMixin,
9
11
  defineCustomElement,
10
12
  validPropertyValues,
13
+ wrapNativeEvent,
11
14
  } from '@justeattakeaway/pie-webc-core';
12
15
  import {
13
16
  property,
@@ -17,7 +20,9 @@ import {
17
20
  } from 'lit/decorators.js';
18
21
  import { ifDefined } from 'lit/directives/if-defined.js';
19
22
  import { classMap, type ClassInfo } from 'lit/directives/class-map.js';
23
+ import { live } from 'lit/directives/live.js';
20
24
  import '@justeattakeaway/pie-icons-webc/dist/IconChevronDown.js';
25
+ import '@justeattakeaway/pie-assistive-text';
21
26
 
22
27
  import styles from './select.scss?inline';
23
28
  import {
@@ -35,8 +40,9 @@ const assistiveTextIdValue = 'assistive-text';
35
40
 
36
41
  /**
37
42
  * @tagname pie-select
43
+ * @event {CustomEvent} change - when the selected option is changed.
38
44
  */
39
- export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
45
+ export class PieSelect extends FormControlMixin(RtlMixin(LitElement)) implements SelectProps {
40
46
  static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };
41
47
 
42
48
  @property({ type: String })
@@ -56,8 +62,14 @@ export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
56
62
  @property({ type: String })
57
63
  public name: SelectProps['name'];
58
64
 
65
+ @property({ type: Array })
66
+ public options: SelectProps['options'] = defaultProps.options;
67
+
68
+ @query('select')
69
+ public focusTarget!: HTMLSelectElement;
70
+
59
71
  @query('select')
60
- public focusTarget!: HTMLElement;
72
+ private _select!: HTMLSelectElement;
61
73
 
62
74
  @queryAssignedElements({ slot: 'leadingIcon', flatten: true })
63
75
  private _leadingIconSlot!: Array<HTMLElement>;
@@ -65,11 +77,94 @@ export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
65
77
  @state()
66
78
  private _hasLeadingIcon = false;
67
79
 
80
+ protected firstUpdated (): void {
81
+ this._internals.setFormValue(this._select.value);
82
+ }
83
+
84
+ /**
85
+ * (Read-only) returns a ValidityState with the validity states that this element is in.
86
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
87
+ */
88
+ public get validity (): ValidityState {
89
+ return this._select.validity;
90
+ }
91
+
92
+ /**
93
+ * Called after the disabled state of the element changes,
94
+ * either because the disabled attribute of this element was added or removed;
95
+ * or because the disabled state changed on a <fieldset> that's an ancestor of this element.
96
+ * @param disabled - The latest disabled state of the select.
97
+ */
98
+ public formDisabledCallback (disabled: boolean): void {
99
+ this.disabled = disabled;
100
+ }
101
+
102
+ /**
103
+ * Called when the form that owns this component is reset.
104
+ * Resets the value to the default select value.
105
+ */
106
+ public formResetCallback (): void {
107
+ const selected = this._select.querySelector('option[selected]');
108
+ this._select.value = selected?.getAttribute('value') ?? '';
109
+ this._select.selectedIndex = selected ? this._select.selectedIndex : 0;
110
+ this._internals.setFormValue(this._select.value);
111
+ }
112
+
113
+ /**
114
+ * Captures the native change event and wraps it in a custom event.
115
+ * @param event - The change event.
116
+ */
117
+ private _handleChange = (event: Event) => {
118
+ // We have to create our own change event because the native one
119
+ // does not penetrate the shadow boundary.
120
+
121
+ // This is because some events set `composed` to `false`.
122
+ // Reference: https://javascript.info/shadow-dom-events#event-composed
123
+ const customChangeEvent = wrapNativeEvent(event);
124
+ this.dispatchEvent(customChangeEvent);
125
+
126
+ this._internals.setFormValue(this._select.value);
127
+ };
128
+
68
129
  private _handleLeadingIconSlotchange () {
69
130
  this._hasLeadingIcon = Boolean(this._leadingIconSlot.length);
70
131
  }
71
132
 
72
- private renderAssistiveText () {
133
+ /**
134
+ * Renders the options from the options property
135
+ * @param options - The options to render
136
+ * @returns A template result with the rendered options
137
+ */
138
+ private renderChildren (options: SelectProps['options']): TemplateResult {
139
+ return html`
140
+ ${options.map((option) => {
141
+ if (option.tag === 'optgroup') {
142
+ return html`
143
+ <optgroup
144
+ ?disabled="${option.disabled}"
145
+ label="${ifDefined(option.label)}">
146
+ ${this.renderChildren(option.options)}
147
+ </optgroup>
148
+ `;
149
+ }
150
+
151
+ return html`
152
+ <option
153
+ .value="${live(option.value)}"
154
+ ?disabled="${option.disabled}"
155
+ ?selected="${option.selected}">
156
+ ${option.text}
157
+ </option>
158
+ `;
159
+ })}
160
+ `;
161
+ }
162
+
163
+ /**
164
+ * Renders the assistive text if available.
165
+ * @returns A template result with the assistive text
166
+ */
167
+ private renderAssistiveText (): TemplateResult | typeof nothing {
73
168
  if (!this.assistiveText) {
74
169
  return nothing;
75
170
  }
@@ -77,8 +172,8 @@ export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
77
172
  return html`
78
173
  <pie-assistive-text
79
174
  id="${assistiveTextIdValue}"
80
- variant=${ifDefined(this.status)}
81
- data-test-id="pie-textarea-assistive-text">
175
+ variant="${ifDefined(this.status)}"
176
+ data-test-id="pie-select-assistive-text">
82
177
  ${this.assistiveText}
83
178
  </pie-assistive-text>
84
179
  `;
@@ -91,6 +186,7 @@ export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
91
186
  status,
92
187
  size,
93
188
  name,
189
+ options,
94
190
  _hasLeadingIcon,
95
191
  } = this;
96
192
 
@@ -106,18 +202,18 @@ export class PieSelect extends RtlMixin(LitElement) implements SelectProps {
106
202
  <div
107
203
  class="${classMap(classes)}"
108
204
  data-test-id="pie-select-shell">
109
- <slot name="leadingIcon" @slotchange=${this._handleLeadingIconSlotchange}></slot>
110
- <select
111
- name=${ifDefined(name)}
112
- ?disabled=${disabled}
113
- aria-describedby=${ifDefined(assistiveText ? assistiveTextIdValue : undefined)}
114
- aria-invalid=${status === 'error' ? 'true' : 'false'}
115
- aria-errormessage="${ifDefined(status === 'error' ? assistiveTextIdValue : undefined)}">
116
- <option value="dog">Dog</option>
117
- <option value="cat">Cat</option>
118
- <option value="hamster">Hamster</option>
119
- </select>
120
- <icon-chevron-down size='s' class='c-select-trailingIcon'></icon-chevron-down>
205
+ <slot name="leadingIcon" @slotchange=${this._handleLeadingIconSlotchange}></slot>
206
+ <select
207
+ data-test-id="pie-select-element"
208
+ name="${ifDefined(name)}"
209
+ ?disabled="${disabled}"
210
+ aria-describedby="${ifDefined(assistiveText ? assistiveTextIdValue : undefined)}"
211
+ aria-invalid="${status === 'error' ? 'true' : 'false'}"
212
+ aria-errormessage="${ifDefined(status === 'error' ? assistiveTextIdValue : undefined)}"
213
+ @change=${this._handleChange}>
214
+ ${this.renderChildren(options)}
215
+ </select>
216
+ <icon-chevron-down size='s' class='c-select-trailingIcon'></icon-chevron-down>
121
217
  </div>
122
218
  ${this.renderAssistiveText()}
123
219
  `;
package/src/react.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { createComponent } from '@lit/react';
2
+ import { createComponent, type EventName } from '@lit/react';
3
3
  import { PieSelect as PieSelectLit } from './index';
4
4
  import { type SelectProps } from './defs';
5
5
 
@@ -10,10 +10,16 @@ const PieSelectReact = createComponent({
10
10
  elementClass: PieSelectLit,
11
11
  react: React,
12
12
  tagName: 'pie-select',
13
- events: {},
13
+ events: {
14
+ onChange: 'change' as EventName<CustomEvent>, // when the selected option is changed.
15
+ },
14
16
  });
15
17
 
16
18
  type ReactBaseType = React.HTMLAttributes<HTMLSelectElement>
17
19
 
20
+ type PieSelectEvents = {
21
+ onChange?: (event: CustomEvent) => void;
22
+ };
23
+
18
24
  export const PieSelect = PieSelectReact as React.ForwardRefExoticComponent<React.PropsWithoutRef<SelectProps>
19
- & React.RefAttributes<PieSelectLit> & ReactBaseType>;
25
+ & React.RefAttributes<PieSelectLit> & PieSelectEvents & ReactBaseType>;
package/dist/defs.d.ts DELETED
@@ -1,29 +0,0 @@
1
- import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
2
- export declare const sizes: readonly ["small", "medium", "large"];
3
- export declare const statusTypes: readonly ["default", "error"];
4
- export interface SelectProps {
5
- /**
6
- * The size of the select component. Can be `small`, `medium` or `large`. Defaults to `medium`.
7
- */
8
- size?: typeof sizes[number];
9
- /**
10
- * Same as the HTML disabled attribute - indicates whether the select is disabled.
11
- */
12
- disabled?: boolean;
13
- /**
14
- * An optional assistive text to display below the select element. Must be provided when the status is success or error.
15
- */
16
- assistiveText?: string;
17
- /**
18
- * The status of the select component / assistive text. Can be default or error.
19
- */
20
- status?: typeof statusTypes[number];
21
- /**
22
- * The name of the select (used as a key/value pair with `value`). This is required in order to work properly with forms.
23
- */
24
- name?: string;
25
- }
26
- type DefaultProps = ComponentDefaultProps<SelectProps, keyof Omit<SelectProps, 'name' | 'assistiveText'>>;
27
- export declare const defaultProps: DefaultProps;
28
- export {};
29
- //# sourceMappingURL=defs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../src/defs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,eAAO,MAAM,KAAK,uCAAwC,CAAC;AAE3D,eAAO,MAAM,WAAW,+BAAgC,CAAC;AAEzD,MAAM,WAAW,WAAW;IACxB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;IAEpC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,YAAY,GAAG,qBAAqB,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAAE,CAAC,CAAC;AAE3G,eAAO,MAAM,YAAY,EAAE,YAI1B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,UAAU,EAIb,MAAM,KAAK,CAAC;AAcb,OAAO,yDAAyD,CAAC;AAGjE,OAAO,EAIH,KAAK,WAAW,EACnB,MAAM,QAAQ,CAAC;AAGhB,cAAc,QAAQ,CAAC;AAEvB,QAAA,MAAM,iBAAiB,eAAe,CAAC;;AAGvC;;GAEG;AACH,qBAAa,SAAU,SAAQ,cAAqB,YAAW,WAAW;IACtE,MAAM,CAAC,iBAAiB;;;;MAA6D;IAI9E,IAAI,+BAAqB;IAGzB,QAAQ,UAAyB;IAIjC,MAAM,sBAAuB;IAG7B,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;IAG5C,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAG1B,WAAW,EAAG,WAAW,CAAC;IAGjC,OAAO,CAAC,gBAAgB,CAAsB;IAG9C,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,4BAA4B;IAIpC,OAAO,CAAC,mBAAmB;IAe3B,MAAM;IAwCN,MAAM,CAAC,MAAM,0BAAqB;CACrC;AAID,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC;KAClC;CACJ"}
@@ -1,3 +0,0 @@
1
- export interface OptionProps {
2
- }
3
- //# sourceMappingURL=defs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/pie-option/defs.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,WAAW;CAC3B"}
@@ -1,15 +0,0 @@
1
- import { LitElement } from 'lit';
2
- import { type OptionProps } from './defs';
3
- declare const componentSelector = "pie-option";
4
- /**
5
- * @tagname pie-option
6
- */
7
- export declare class PieOption extends LitElement implements OptionProps {
8
- }
9
- declare global {
10
- interface HTMLElementTagNameMap {
11
- [componentSelector]: PieOption;
12
- }
13
- }
14
- export {};
15
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pie-option/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,QAAA,MAAM,iBAAiB,eAAe,CAAC;AAEvC;;GAEG;AACH,qBAAa,SAAU,SAAQ,UAAW,YAAW,WAAW;CAE/D;AAID,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC;KAClC;CACJ"}
@@ -1,9 +0,0 @@
1
- import { LitElement as e } from "lit";
2
- import { defineCustomElement as o } from "@justeattakeaway/pie-webc-core";
3
- const t = "pie-option";
4
- class n extends e {
5
- }
6
- o(t, n);
7
- export {
8
- n as PieOption
9
- };
@@ -1,7 +0,0 @@
1
- import * as React from 'react';
2
- import { PieOption as PieOptionLit } from './index';
3
- import { type OptionProps } from './defs';
4
- export * from './defs';
5
- type ReactBaseType = React.HTMLAttributes<HTMLOptionElement>;
6
- export declare const PieOption: React.ForwardRefExoticComponent<OptionProps & React.RefAttributes<PieOptionLit> & ReactBaseType>;
7
- //# sourceMappingURL=react.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/pie-option/react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,cAAc,QAAQ,CAAC;AAUvB,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAA;AAE5D,eAAO,MAAM,SAAS,kGACkC,CAAC"}
@@ -1,13 +0,0 @@
1
- import * as e from "react";
2
- import { createComponent as t } from "@lit/react";
3
- import { PieOption as o } from "./index.js";
4
- const i = t({
5
- displayName: "PieOption",
6
- elementClass: o,
7
- react: e,
8
- tagName: "pie-option",
9
- events: {}
10
- }), a = i;
11
- export {
12
- a as PieOption
13
- };
@@ -1,3 +0,0 @@
1
- export interface OptionGroupProps {
2
- }
3
- //# sourceMappingURL=defs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/pie-option-group/defs.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,gBAAgB;CAChC"}
@@ -1,15 +0,0 @@
1
- import { LitElement } from 'lit';
2
- import { type OptionGroupProps } from './defs';
3
- declare const componentSelector = "pie-option-group";
4
- /**
5
- * @tagname pie-option-group
6
- */
7
- export declare class PieOptionGroup extends LitElement implements OptionGroupProps {
8
- }
9
- declare global {
10
- interface HTMLElementTagNameMap {
11
- [componentSelector]: PieOptionGroup;
12
- }
13
- }
14
- export {};
15
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pie-option-group/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,QAAA,MAAM,iBAAiB,qBAAqB,CAAC;AAE7C;;GAEG;AACH,qBAAa,cAAe,SAAQ,UAAW,YAAW,gBAAgB;CAEzE;AAID,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,cAAc,CAAC;KACvC;CACJ"}
@@ -1,9 +0,0 @@
1
- import { LitElement as o } from "lit";
2
- import { defineCustomElement as e } from "@justeattakeaway/pie-webc-core";
3
- const t = "pie-option-group";
4
- class n extends o {
5
- }
6
- e(t, n);
7
- export {
8
- n as PieOptionGroup
9
- };
@@ -1,7 +0,0 @@
1
- import * as React from 'react';
2
- import { PieOptionGroup as PieOptionGroupLit } from './index';
3
- import { type OptionGroupProps } from './defs';
4
- export * from './defs';
5
- type ReactBaseType = React.HTMLAttributes<HTMLOptGroupElement>;
6
- export declare const PieOptionGroup: React.ForwardRefExoticComponent<OptionGroupProps & React.RefAttributes<PieOptionGroupLit> & ReactBaseType>;
7
- //# sourceMappingURL=react.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/pie-option-group/react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,cAAc,QAAQ,CAAC;AAUvB,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAA;AAE9D,eAAO,MAAM,cAAc,4GACkC,CAAC"}
@@ -1,13 +0,0 @@
1
- import * as o from "react";
2
- import { createComponent as e } from "@lit/react";
3
- import { PieOptionGroup as t } from "./index.js";
4
- const p = e({
5
- displayName: "PieOptionGroup",
6
- elementClass: t,
7
- react: o,
8
- tagName: "pie-option-group",
9
- events: {}
10
- }), n = p;
11
- export {
12
- n as PieOptionGroup
13
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C,cAAc,QAAQ,CAAC;AAUvB,KAAK,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAA;AAE5D,eAAO,MAAM,SAAS,kGACkC,CAAC"}
@@ -1,3 +0,0 @@
1
- import type React from 'react';
2
-
3
- export type ReactBaseType = React.HTMLAttributes<HTMLOptionElement>
@@ -1,3 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
2
- export interface OptionProps {
3
- }
@@ -1,20 +0,0 @@
1
- import { LitElement } from 'lit';
2
- import { defineCustomElement } from '@justeattakeaway/pie-webc-core';
3
- import { type OptionProps } from './defs';
4
-
5
- const componentSelector = 'pie-option';
6
-
7
- /**
8
- * @tagname pie-option
9
- */
10
- export class PieOption extends LitElement implements OptionProps {
11
-
12
- }
13
-
14
- defineCustomElement(componentSelector, PieOption);
15
-
16
- declare global {
17
- interface HTMLElementTagNameMap {
18
- [componentSelector]: PieOption;
19
- }
20
- }
@@ -1,3 +0,0 @@
1
- import type React from 'react';
2
-
3
- export type ReactBaseType = React.HTMLAttributes<HTMLOptGroupElement>
@@ -1,3 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
2
- export interface OptionGroupProps {
3
- }
@@ -1,20 +0,0 @@
1
- import { LitElement } from 'lit';
2
- import { defineCustomElement } from '@justeattakeaway/pie-webc-core';
3
- import { type OptionGroupProps } from './defs';
4
-
5
- const componentSelector = 'pie-option-group';
6
-
7
- /**
8
- * @tagname pie-option-group
9
- */
10
- export class PieOptionGroup extends LitElement implements OptionGroupProps {
11
-
12
- }
13
-
14
- defineCustomElement(componentSelector, PieOptionGroup);
15
-
16
- declare global {
17
- interface HTMLElementTagNameMap {
18
- [componentSelector]: PieOptionGroup;
19
- }
20
- }