Skip to content

Commit 205ceee

Browse files
authored
feat: added uui-combobox elements
* Added uui-combobox element * Added uui-comboxbox-list element * Added uui-combobox-list-option element * Added autocomplemete attribute to uui-input
1 parent 3ff1f3a commit 205ceee

33 files changed

+3917
-26
lines changed

package-lock.json

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/uui-base/lib/events/UUISelectableEvent.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,11 @@ import { UUIEvent } from './UUIEvent';
44
export class UUISelectableEvent extends UUIEvent<{}, SelectableMixinInterface> {
55
public static readonly SELECTED = 'selected';
66
public static readonly UNSELECTED = 'unselected';
7+
8+
constructor(evName: string, eventInit: any | null = {}) {
9+
super(evName, {
10+
...{ bubbles: true },
11+
...eventInit,
12+
});
13+
}
714
}

packages/uui-base/lib/mixins/SelectableMixin.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type Constructor<T = {}> = new (...args: any[]) => T;
77

88
export declare class SelectableMixinInterface extends LitElement {
99
selectable: boolean;
10+
unselectable: boolean;
1011
selected: boolean;
1112
}
1213

@@ -43,6 +44,8 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
4344
this.requestUpdate('selected', oldVal);
4445
}
4546

47+
protected unselectable = true;
48+
4649
/**
4750
* Attribute applied when the element is selected.
4851
* @attr
@@ -53,28 +56,34 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
5356

5457
constructor(...args: any[]) {
5558
super(...args);
56-
this.addEventListener('click', this._toggleSelect);
59+
this.addEventListener('click', this._handleClick);
5760
this.addEventListener('keydown', this.handleSelectKeydown);
5861
}
5962

6063
private handleSelectKeydown(e: KeyboardEvent) {
6164
if (e.key !== ' ' && e.key !== 'Enter') return;
6265
e.preventDefault();
63-
this._toggleSelect();
66+
this._handleClick();
67+
}
68+
69+
private _select() {
70+
if (!this.selectable) return;
71+
this.selected = true;
72+
this.dispatchEvent(new UUISelectableEvent(UUISelectableEvent.SELECTED));
6473
}
6574

66-
private _toggleSelect() {
67-
if (this.selectable === false) return;
68-
this.selected = !this.selected;
75+
private _unselect() {
76+
if (!this.unselectable) return;
77+
this.selected = false;
78+
this.dispatchEvent(new UUISelectableEvent(UUISelectableEvent.UNSELECTED));
79+
}
6980

70-
this.dispatchEvent(
71-
new UUISelectableEvent(
72-
this.selected
73-
? UUISelectableEvent.SELECTED
74-
: UUISelectableEvent.UNSELECTED,
75-
this
76-
)
77-
);
81+
private _handleClick() {
82+
if (this.unselectable === false) {
83+
this._select();
84+
} else {
85+
this.selected ? this._unselect() : this._select();
86+
}
7887
}
7988
}
8089
// prettier-ignore

packages/uui-button/lib/uui-button.element.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ export class UUIButtonElement extends LabelMixin('', LitElement) {
5454
--uui-button-padding-top-factor: 1;
5555
--uui-button-padding-bottom-factor: 1;
5656
57+
height: var(--uui-button-height, auto);
58+
max-height: 100%;
59+
5760
text-align: center;
5861
font-weight: var(
5962
--uui-button-font-weight,
@@ -88,7 +91,6 @@ export class UUIButtonElement extends LabelMixin('', LitElement) {
8891
8992
button {
9093
height: 100%;
91-
min-height: var(--uui-button-height, auto);
9294
width: 100%;
9395
9496
padding: calc(calc(8 / 15 * 1em) * var(--uui-button-padding-top-factor))

packages/uui-combobox-list/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# uui-combobox-list
2+
3+
![npm](https://img.shields.io/npm/v/@umbraco-ui/uui-combobox-list?logoColor=%231B264F)
4+
5+
Umbraco style combobox-list component.
6+
7+
## Installation
8+
9+
### ES imports
10+
11+
```zsh
12+
npm i @umbraco-ui/uui-combobox-list
13+
```
14+
15+
Import the registration of `<uui-combobox-list>` via:
16+
17+
```javascript
18+
import '@umbraco-ui/uui-combobox-list';
19+
```
20+
21+
When looking to leverage the `UUIComboboxListElement` base class as a type and/or for extension purposes, do so via:
22+
23+
```javascript
24+
import { UUIComboboxListElement } from '@umbraco-ui/uui-combobox-list';
25+
```
26+
27+
## Usage
28+
29+
```html
30+
<uui-combobox-list></uui-combobox-list>
31+
```
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
2+
import { UUIComboboxListElement } from './uui-combobox-list.element';
3+
4+
export class UUIComboboxListEvent extends UUIEvent<UUIComboboxListElement> {
5+
public static readonly CHANGE: string = 'change';
6+
7+
constructor(evName: string, eventInit: any | null = {}) {
8+
super(evName, {
9+
...{ bubbles: true },
10+
...eventInit,
11+
});
12+
}
13+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './uui-combobox-list.element';
2+
export * from './uui-combobox-list-option.element';
3+
export * from './UUIComboboxListEvent';
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
2+
import { css, html, LitElement } from 'lit';
3+
import { property, state } from 'lit/decorators.js';
4+
import { ActiveMixin, SelectableMixin } from '@umbraco-ui/uui-base/lib/mixins';
5+
6+
/**
7+
* @element uui-combobox-list-option
8+
* @slot default - For option content
9+
* @description - An option to be used within uui-combobox-list
10+
*/
11+
@defineElement('uui-combobox-list-option')
12+
export class UUIComboboxListOptionElement extends SelectableMixin(
13+
ActiveMixin(LitElement)
14+
) {
15+
static styles = [
16+
css`
17+
:host {
18+
position: relative;
19+
cursor: pointer;
20+
margin: 0 6px;
21+
border-radius: var(--uui-border-radius);
22+
outline: 2px solid transparent;
23+
outline-offset: -2px;
24+
}
25+
:host(:first-child) {
26+
margin-top: 6px;
27+
}
28+
:host(:last-child) {
29+
margin-bottom: 6px;
30+
}
31+
32+
:host([selected]):host([active])::after {
33+
display: block;
34+
content: '';
35+
position: absolute;
36+
inset: 0px;
37+
outline: white solid 2px;
38+
outline-offset: -4px;
39+
}
40+
41+
:host::before {
42+
display: block;
43+
content: '';
44+
opacity: 0;
45+
position: absolute;
46+
inset: 0;
47+
background-color: var(--uui-interface-select);
48+
}
49+
50+
:host(:hover)::before {
51+
opacity: 0.15;
52+
border-radius: var(--uui-border-radius);
53+
}
54+
55+
:host([disabled]) {
56+
cursor: auto;
57+
color: var(--uui-interface-surface-contrast-disabled);
58+
background-color: var(--uui-interface-surface-disabled);
59+
}
60+
:host([disabled]:hover) {
61+
background-color: var(--uui-interface-surface-disabled);
62+
}
63+
64+
:host([active]) {
65+
outline-color: var(--uui-interface-outline);
66+
}
67+
68+
:host([selected]) {
69+
color: var(--uui-interface-select-contrast);
70+
background-color: var(--uui-interface-select);
71+
}
72+
:host([selected]:hover) {
73+
color: var(--uui-interface-select-contrast-hover);
74+
background-color: var(--uui-interface-select-hover);
75+
}
76+
:host([selected][disabled]) {
77+
color: var(--uui-interface-select-contrast-disabled);
78+
background-color: var(--uui-interface-select-disabled);
79+
}
80+
`,
81+
];
82+
83+
private _value: string | undefined;
84+
85+
@state()
86+
private _disabled = false;
87+
88+
@state() _displayValue = '';
89+
90+
/**
91+
* Value of the option.
92+
* @type { string }
93+
* @attr
94+
* @default ""
95+
*/
96+
@property({ type: String })
97+
public get value(): string {
98+
return this._value ? this._value : this.textContent?.trim() || '';
99+
}
100+
public set value(newValue: string) {
101+
const oldValue = this._value;
102+
this._value = newValue;
103+
this.requestUpdate('value', oldValue);
104+
}
105+
106+
/**
107+
* A readable value.
108+
* @type { string }
109+
* @attr
110+
* @default ""
111+
*/
112+
@property({ type: String, attribute: 'display-value' })
113+
public get displayValue() {
114+
return this._displayValue
115+
? this._displayValue
116+
: this.textContent?.trim() || '';
117+
}
118+
public set displayValue(newValue) {
119+
const oldValue = this._displayValue;
120+
this._displayValue = newValue;
121+
this.requestUpdate('displayValue', oldValue);
122+
}
123+
124+
/**
125+
* Determines if the options is disabled. If true the option can't be selected
126+
* @type { boolean }
127+
* @attr
128+
* @default false
129+
*/
130+
@property({ type: Boolean, reflect: true })
131+
public get disabled() {
132+
return this._disabled;
133+
}
134+
public set disabled(newValue) {
135+
const oldValue = this._disabled;
136+
this._disabled = newValue;
137+
this.selectable = !this._disabled;
138+
this.requestUpdate('disabled', oldValue);
139+
}
140+
141+
constructor() {
142+
super();
143+
this.selectable = true;
144+
this.unselectable = false;
145+
}
146+
147+
render() {
148+
return html`<slot></slot>`;
149+
}
150+
}
151+
152+
declare global {
153+
interface HTMLElementTagNameMap {
154+
'uui-combobox-list-option': UUIComboboxListOptionElement;
155+
}
156+
}

0 commit comments

Comments
 (0)