import { Story, Meta, html, Preview } from '@open-wc/demoing-storybook'; import { loadDefaultFeedbackMessages, Required } from '@lion/validate'; import '../lion-option.js'; import '../lion-options.js'; import '../lion-select-rich.js'; # Select Rich `lion-select-rich` component is a 'rich' version of the native `` doesn't provide enough styling/theming/user interaction opportunities. Its implementation is based on the following Design pattern: {html` Red Hotpink Teal `} ```html Red Hotpink Teal ``` ## Features - Fully accessible - Flexible api - Fully customizable option elements - Fully customizable invoker element - Mimics native select interaction mode (windows/linux and mac) ## How to use ### Installation ```sh npm i --save @lion/select-rich ``` ```js import '@lion/select-rich/lion-select-rich.js'; import '@lion/select-rich/lion-options.js'; import '@lion/select-rich/lion-option.js'; ``` > No need to npm install `@lion/option` separately, it comes with the rich select as a dependency ## Examples ### Model value You can set the full `modelValue` for each option, which includes the checked property for whether it is checked or not. ```html Red ``` ### Options with HTML The main feature of this rich select that makes it rich, is that your options can contain HTML. {html`

I am red

and multi Line

I am hotpink

and multi Line

I am teal

and multi Line

`}
```html

I am red

and multi Line

I am hotpink

and multi Line

I am teal

and multi Line

``` ### Many Options with Scrolling {html`

I am red

I am hotpink

I am teal

I am green

I am blue

`}
```html

I am red

I am hotpink

I am teal

I am green

I am blue

``` ### Read only prefilled You can set the rich select as read only. This will block the user from opening the select. The readonly attribute is delegated to the invoker for disabling opening the overlay, and for styling purposes. {html` Red Hotpink Teal `} ### Disabled You can set the `disabled` attribute to disable either specific options or the entire select. If you disable the entire select, the disabled attribute is also delegated to the invoker, similar to readonly. {html` Red Hotpink Teal Red Blue Hotpink Green Teal `} ```html Red Hotpink Teal ``` ```html Red Blue Hotpink Green Teal ``` ### Validation Validation can be used on this field as well, same as with other fields. Below is an example with required. It can be triggered by opening the select and selecting a valid option, then selecting the first option again, of which the `modelValue` is `null`. {() => { loadDefaultFeedbackMessages(); return html` select a color Red Hotpink Teal `; }} ```js import { loadDefaultFeedbackMessages, Required } from '@lion/validate'; ``` ```html select a color Red Hotpink Teal ``` ### Render options The choiceValue can also be a complex value like an Object. It is up to you how to render this Object in the DOM. {() => { const objs = [ { type: 'mastercard', label: 'Master Card', amount: 12000, active: true }, { type: 'visacard', label: 'Visa Card', amount: 0, active: false }, ]; function showOutput() { document.getElementById('demoRenderOutput').innerHTML = JSON.stringify( this.checkedValue, null, 2, ); } return html` ${objs.map( obj => html` ${obj.label} `, )}

Full value:


    `;
  }}
```js const objs = [ { type: 'mastercard', label: 'Master Card', amount: 12000, active: true }, { type: 'visacard', label: 'Visa Card', amount: 0, active: false }, ]; ``` ```html ${objs.map( obj => html` ${obj.label} `, )} ``` ### Interaction Mode You can set the interaction mode to either `mac` or `windows/linux`. By default, it will choose based on the user Operating System, but it can be forced. This changes the keyboard interaction. {html` Red Hotpink Teal Red Hotpink Teal `} ```html Red Hotpink Teal ``` ```html Red Hotpink Teal ``` ### Checked index & value You can get/set the checkedIndex and checkedValue. {html`
{ const selectEl = document.getElementById('checkedRichSelect'); selectEl.checkedIndex = e.target.value; }} >
Red Hotpink Teal `}
```html Red Hotpink Teal ``` ```js console.log(`checkedIndex: ${selectEl.checkedIndex}`); // 1 console.log(`checkedValue: ${selectEl.checkedValue}`); // 'hotpink' selectEl.checkedIndex = 0; console.log(`checkedIndex: ${selectEl.checkedIndex}`); // 0 console.log(`checkedValue: ${selectEl.checkedValue}`); // 'red' ``` ### Custom Invoker You can provide a custom invoker using the invoker slot. This means it will get the selected value(s) as an input property `.selectedElement`. You can use this `selectedElement` to then render the content to your own invoker. ```html ... ``` An example of how such a custom invoker class could look like: ```js class MyInvokerButton extends LitElement() { static get properties() { return { selectedElement: { type: Object, }; } } _contentTemplate() { if (this.selectedElement) { const labelNodes = Array.from(this.selectedElement.querySelectorAll('*')); // Nested html in the selected option if (labelNodes.length > 0) { // Cloning is important if you plan on passing nodes straight to a lit template return labelNodes.map(node => node.cloneNode(true)); } // Or if it is just text inside the selected option, no html return this.selectedElement.textContent; } return ``; } render() { return html`
${this._contentTemplate()}
`; } } ``` > This example only works if your option elements don't have ShadowDOM boundaries themselves. > Cloning deeply only works up until the first shadow boundary.