@kubex/zinc 1.0.16 → 1.0.18
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/dist/custom-elements.json +43 -5
- package/dist/vscode.html-custom-data.json +1 -0
- package/dist/web-types.json +9 -3
- package/dist/zn.d.ts +7 -3
- package/dist/zn.min.js +109 -96
- package/docs/pages/components/select.md +23 -2
- package/package.json +1 -1
- package/src/components/button/button.scss +1 -0
- package/src/components/checkbox/checkbox.component.ts +10 -5
- package/src/components/checkbox/checkbox.scss +48 -1
- package/src/components/data-table/data-table.component.ts +35 -9
- package/src/components/note/note.component.ts +7 -4
- package/src/components/note/note.scss +5 -0
- package/src/components/select/select.component.ts +85 -53
- package/src/components/select/select.scss +21 -0
- package/src/components/style/style.component.ts +1 -1
|
@@ -41,7 +41,6 @@ on [form controls](/getting-started/form-controls) to learn more about form subm
|
|
|
41
41
|
|
|
42
42
|
### Distinct Selects
|
|
43
43
|
|
|
44
|
-
|
|
45
44
|
```html:preview
|
|
46
45
|
|
|
47
46
|
<div class="form-spacing">
|
|
@@ -60,7 +59,6 @@ on [form controls](/getting-started/form-controls) to learn more about form subm
|
|
|
60
59
|
|
|
61
60
|
### Conditional Selects
|
|
62
61
|
|
|
63
|
-
|
|
64
62
|
```html:preview
|
|
65
63
|
|
|
66
64
|
<div class="form-spacing">
|
|
@@ -423,6 +421,29 @@ so that we can consider whether the pattern needs to be updated.
|
|
|
423
421
|
</zn-select>
|
|
424
422
|
```
|
|
425
423
|
|
|
424
|
+
### Checkbox Prefix
|
|
425
|
+
|
|
426
|
+
You can place a checkbox in the `prefix` slot to visually join it to the select. The checkbox will match the height of
|
|
427
|
+
the control and can be interacted with independently (clicking or toggling it won’t open the select).
|
|
428
|
+
|
|
429
|
+
```html:preview
|
|
430
|
+
<zn-select label="Notify me about" help-text="Use the checkbox to enable/disable notifications; choose a channel with the select">
|
|
431
|
+
<zn-checkbox slot="prefix" aria-label="Enable notifications"></zn-checkbox>
|
|
432
|
+
<zn-option value="email">Email</zn-option>
|
|
433
|
+
<zn-option value="sms">SMS</zn-option>
|
|
434
|
+
<zn-option value="push">Push</zn-option>
|
|
435
|
+
</zn-select>
|
|
436
|
+
|
|
437
|
+
<br />
|
|
438
|
+
|
|
439
|
+
<zn-select label="Large with checkbox" size="large" value="email">
|
|
440
|
+
<zn-checkbox slot="prefix" size="large" aria-label="Enable notifications"></zn-checkbox>
|
|
441
|
+
<zn-option value="email">Email</zn-option>
|
|
442
|
+
<zn-option value="sms">SMS</zn-option>
|
|
443
|
+
<zn-option value="push">Push</zn-option>
|
|
444
|
+
</zn-select>
|
|
445
|
+
```
|
|
446
|
+
|
|
426
447
|
### Custom Tags
|
|
427
448
|
|
|
428
449
|
When multiple options can be selected, you can provide custom tags by passing a function to the `getTag` property. Your
|
package/package.json
CHANGED
|
@@ -7,9 +7,9 @@ import {ifDefined} from "lit/directives/if-defined.js";
|
|
|
7
7
|
import {live} from "lit/directives/live.js";
|
|
8
8
|
import {property, query, state} from 'lit/decorators.js';
|
|
9
9
|
import {watch} from '../../internal/watch';
|
|
10
|
-
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
11
10
|
import ZincElement from '../../internal/zinc-element';
|
|
12
11
|
import ZnIcon from "../icon";
|
|
12
|
+
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
13
13
|
|
|
14
14
|
import styles from './checkbox.scss';
|
|
15
15
|
|
|
@@ -289,10 +289,15 @@ export default class ZnCheckbox extends ZincElement implements ZincFormControl {
|
|
|
289
289
|
? ' control--indeterminate'
|
|
290
290
|
: ''}"
|
|
291
291
|
class="checkbox__control">
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
292
|
+
<svg viewBox="0 0 24 24"
|
|
293
|
+
fill="none"
|
|
294
|
+
stroke="currentColor"
|
|
295
|
+
stroke-width="4"
|
|
296
|
+
stroke-linecap="round"
|
|
297
|
+
stroke-linejoin="round"
|
|
298
|
+
class="svg-icon">
|
|
299
|
+
<polyline class="checkbox__checked-icon" points="20 6 9 17 4 12"></polyline>
|
|
300
|
+
</svg>
|
|
296
301
|
${!this.checked && this.indeterminate
|
|
297
302
|
? html`
|
|
298
303
|
<zn-icon
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
.form-control {
|
|
9
9
|
display: flex;
|
|
10
10
|
flex-direction: column;
|
|
11
|
+
height: 100%;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
.form-control .form-control__label {
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
color: var(--zn-input-label-color);
|
|
24
25
|
vertical-align: middle;
|
|
25
26
|
cursor: pointer;
|
|
27
|
+
height: 100%;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
.checkbox--small {
|
|
@@ -76,7 +78,6 @@
|
|
|
76
78
|
pointer-events: none;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
.checkbox__checked-icon,
|
|
80
81
|
.checkbox__indeterminate-icon {
|
|
81
82
|
--icon-size: var(--toggle-size);
|
|
82
83
|
--icon-color: var(--zn-color-neutral-0);
|
|
@@ -86,6 +87,32 @@
|
|
|
86
87
|
height: var(--toggle-size);
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
.svg-icon {
|
|
91
|
+
width: 70%;
|
|
92
|
+
height: 70%;
|
|
93
|
+
--icon-color: var(--zn-color-neutral-0);
|
|
94
|
+
|
|
95
|
+
.checkbox__checked-icon {
|
|
96
|
+
stroke-dasharray: 24;
|
|
97
|
+
stroke-dashoffset: 24;
|
|
98
|
+
transition: stroke-dashoffset 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.checkbox--indeterminate .svg-icon {
|
|
103
|
+
color: transparent;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.checkbox--checked {
|
|
107
|
+
.svg-icon {
|
|
108
|
+
color: var(--zn-color-neutral-0);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.checkbox__checked-icon {
|
|
112
|
+
stroke-dashoffset: 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
89
116
|
/* Hover */
|
|
90
117
|
.checkbox:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control:hover {
|
|
91
118
|
border-color: var(--zn-input-border-color-hover);
|
|
@@ -200,3 +227,23 @@
|
|
|
200
227
|
outline: 1px solid var(--zn-color-purple-600);
|
|
201
228
|
transition: var(--zn-transition-medium) all;
|
|
202
229
|
}
|
|
230
|
+
|
|
231
|
+
/** Select prefix slot */
|
|
232
|
+
:host([slot="prefix"]) {
|
|
233
|
+
height: 100%;
|
|
234
|
+
aspect-ratio: 1;
|
|
235
|
+
|
|
236
|
+
.checkbox__control {
|
|
237
|
+
height: 100%;
|
|
238
|
+
width: 100%;
|
|
239
|
+
border-left: unset;
|
|
240
|
+
border-top: unset;
|
|
241
|
+
border-bottom: unset;
|
|
242
|
+
box-shadow: unset;
|
|
243
|
+
background-color: var(--zn-color-purple-50);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.checkbox--checked .checkbox__control {
|
|
247
|
+
background-color: var(--zn-color-primary-600);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -417,21 +417,47 @@ export default class ZnDataTable extends ZincElement {
|
|
|
417
417
|
|
|
418
418
|
// add groups to the current rows
|
|
419
419
|
const toAdd = this.groups.split(',').map(g => g.trim()).filter(g => g.length > 0);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
420
|
+
|
|
421
|
+
const hasWildcard = toAdd.includes('*');
|
|
422
|
+
const explicitGroups = new Set(
|
|
423
|
+
toAdd
|
|
424
|
+
.filter(g => g !== '*')
|
|
425
|
+
.map(g => this.humanize(g))
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
// pre-create explicit groups
|
|
429
|
+
explicitGroups.forEach((group) => {
|
|
430
|
+
if (!groupedRows[group]) {
|
|
431
|
+
groupedRows[group] = [];
|
|
423
432
|
}
|
|
424
433
|
});
|
|
425
434
|
|
|
435
|
+
// pre-create wildcard grouping if requested
|
|
436
|
+
if (hasWildcard) {
|
|
437
|
+
groupedRows['*'] = [];
|
|
438
|
+
}
|
|
439
|
+
|
|
426
440
|
this._rows.forEach((row: Row) => {
|
|
427
441
|
const groupCell = row.cells.find((cell: Cell) => cell.column === this.groupBy);
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
442
|
+
const rawGroupValue = groupCell ? groupCell.text : 'Ungrouped';
|
|
443
|
+
const groupValue = this.humanize(rawGroupValue);
|
|
444
|
+
|
|
445
|
+
if (explicitGroups.has(groupValue)) {
|
|
446
|
+
groupedRows[groupValue].push(row);
|
|
447
|
+
return;
|
|
431
448
|
}
|
|
432
449
|
|
|
433
|
-
if (
|
|
434
|
-
groupedRows[
|
|
450
|
+
if (hasWildcard) {
|
|
451
|
+
groupedRows['*'].push(row);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// If no groups specified, or handling ungrouped fallback, create groups dynamically
|
|
456
|
+
if (!this.groups || groupValue === 'Ungrouped') {
|
|
457
|
+
if (!groupedRows[groupValue]) {
|
|
458
|
+
groupedRows[groupValue] = [];
|
|
459
|
+
}
|
|
460
|
+
groupedRows[groupValue].push(row);
|
|
435
461
|
}
|
|
436
462
|
});
|
|
437
463
|
|
|
@@ -447,7 +473,7 @@ export default class ZnDataTable extends ZincElement {
|
|
|
447
473
|
<zn-sp flush>
|
|
448
474
|
${Object.keys(groupedRows).map((groupKey) => html`
|
|
449
475
|
<div class="table-group">
|
|
450
|
-
<h3 class="table-group__title">${groupKey === "Ungrouped" ? "" : groupKey}</h3>
|
|
476
|
+
<h3 class="table-group__title">${(groupKey === "Ungrouped" || groupKey === "*") ? "" : groupKey}</h3>
|
|
451
477
|
${this.renderTableData(groupedRows[groupKey])}
|
|
452
478
|
</div>`
|
|
453
479
|
)}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type colors} from "../data-select/providers/color-data-provider";
|
|
3
3
|
import {type CSSResultGroup, html, unsafeCSS} from 'lit';
|
|
4
|
+
import {HasSlotController} from "../../internal/slot";
|
|
4
5
|
import {property, state} from "lit/decorators.js";
|
|
5
6
|
import ZincElement from '../../internal/zinc-element';
|
|
6
7
|
|
|
7
8
|
import styles from './note.scss';
|
|
8
|
-
import {HasSlotController} from "../../internal/slot";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @summary Short summary of the component's intended use.
|
|
@@ -61,9 +61,12 @@ export default class ZnNote extends ZincElement {
|
|
|
61
61
|
})}">
|
|
62
62
|
<div class="note__header">
|
|
63
63
|
<slot name="caption" class="note__header__caption">${this.caption}</slot>
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
64
|
+
<div class="note__header__end">
|
|
65
|
+
<slot name="date" class="note__header__date">
|
|
66
|
+
<small>${this.date}</small>
|
|
67
|
+
</slot>
|
|
68
|
+
<slot name="action"></slot>
|
|
69
|
+
</div>
|
|
67
70
|
</div>
|
|
68
71
|
|
|
69
72
|
${this.expanded && showExpandableButton ?
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { type CSSResultGroup, html, nothing, PropertyValues, type TemplateResult, unsafeCSS } from 'lit';
|
|
1
|
+
import {animateTo, stopAnimations} from '../../internal/animate.js';
|
|
2
|
+
import {classMap} from "lit/directives/class-map.js";
|
|
4
3
|
import {deepQuerySelectorAll} from "../../utilities/query";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
4
|
+
import {FormControlController} from "../../internal/form";
|
|
5
|
+
import {getAnimation, setDefaultAnimation} from "../../utilities/animation-registry";
|
|
6
|
+
import {HasSlotController} from "../../internal/slot";
|
|
7
|
+
import {html, nothing, unsafeCSS} from 'lit';
|
|
8
|
+
import {LocalizeController} from "../../utilities/localize";
|
|
9
|
+
import {property, query, state} from 'lit/decorators.js';
|
|
10
|
+
import {scrollIntoView} from "../../internal/scroll";
|
|
11
|
+
import {unsafeHTML} from "lit/directives/unsafe-html.js";
|
|
12
|
+
import {waitForEvent} from "../../internal/event";
|
|
13
|
+
import {watch} from '../../internal/watch';
|
|
14
14
|
import ZincElement from '../../internal/zinc-element';
|
|
15
15
|
import ZnChip from "../chip";
|
|
16
16
|
import ZnIcon from "../icon";
|
|
17
17
|
import ZnPopup from "../popup";
|
|
18
|
-
import type {
|
|
19
|
-
import type {
|
|
18
|
+
import type {CSSResultGroup, PropertyValues, TemplateResult} from 'lit';
|
|
19
|
+
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
20
|
+
import type {ZnRemoveEvent} from "../../events/zn-remove";
|
|
20
21
|
import type ZnOption from "../option";
|
|
21
22
|
|
|
22
23
|
import styles from './select.scss';
|
|
@@ -90,12 +91,14 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
90
91
|
@query('.select__display-input') displayInput: HTMLInputElement;
|
|
91
92
|
@query('.select__value-input') valueInput: HTMLInputElement;
|
|
92
93
|
@query('.select__listbox') listbox: HTMLSlotElement;
|
|
94
|
+
@query('slot[name="prefix"]') prefixSlot: HTMLSlotElement;
|
|
93
95
|
|
|
94
96
|
@state() private hasFocus = false;
|
|
95
97
|
@state() displayLabel = '';
|
|
96
98
|
@state() currentOption: ZnOption;
|
|
97
99
|
@state() selectedOptions: ZnOption[] = [];
|
|
98
100
|
@state() private valueHasChanged: boolean = false;
|
|
101
|
+
@state() private hasCheckboxPrefix: boolean = false;
|
|
99
102
|
|
|
100
103
|
/** The name of the select, submitted as a name/value pair with form data. */
|
|
101
104
|
@property() name = '';
|
|
@@ -142,73 +145,75 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
142
145
|
}) defaultValue: string | string[] = '';
|
|
143
146
|
|
|
144
147
|
/** The select's size. */
|
|
145
|
-
@property({
|
|
148
|
+
@property({reflect: true}) size: 'small' | 'medium' | 'large' = 'medium';
|
|
146
149
|
|
|
147
150
|
/** Placeholder text to show as a hint when the select is empty. */
|
|
148
151
|
@property() placeholder = '';
|
|
149
152
|
|
|
150
153
|
/** Allows more than one option to be selected. */
|
|
151
|
-
@property({
|
|
154
|
+
@property({type: Boolean, reflect: true}) multiple = false;
|
|
152
155
|
|
|
153
156
|
/** Max number of options that can be selected when `multiple` is true. Set to 0 to allow unlimited selections. */
|
|
154
|
-
@property({
|
|
157
|
+
@property({attribute: 'max-options', type: Number}) maxOptions = 0;
|
|
155
158
|
|
|
156
159
|
/**
|
|
157
160
|
* The maximum number of selected options to show when `multiple` is true. After the maximum, "+n" will be shown to
|
|
158
161
|
* indicate the number of additional items that are selected. Set to 0 to remove the limit.
|
|
159
162
|
*/
|
|
160
|
-
@property({
|
|
163
|
+
@property({attribute: 'max-options-visible', type: Number}) maxOptionsVisible = 3;
|
|
161
164
|
|
|
162
165
|
/** Disables the select control. */
|
|
163
|
-
@property({
|
|
166
|
+
@property({type: Boolean, reflect: true}) disabled = false;
|
|
164
167
|
|
|
165
168
|
/** Adds a clear button when the select is not empty. */
|
|
166
|
-
@property({
|
|
169
|
+
@property({type: Boolean}) clearable = false;
|
|
167
170
|
|
|
168
171
|
/**
|
|
169
172
|
* Indicates whether or not the select is open. You can toggle this attribute to show and hide the menu, or you can
|
|
170
173
|
* use the `show()` and `hide()` methods and this attribute will reflect the select's open state.
|
|
171
174
|
*/
|
|
172
|
-
@property({
|
|
175
|
+
@property({type: Boolean, reflect: true}) open = false;
|
|
173
176
|
|
|
174
177
|
/**
|
|
175
178
|
* Enable this option to prevent the listbox from being clipped when the component is placed inside a container with
|
|
176
179
|
* `overflow: auto|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all, scenarios.
|
|
177
180
|
*/
|
|
178
|
-
@property({
|
|
181
|
+
@property({type: Boolean}) hoist = false;
|
|
179
182
|
|
|
180
183
|
/** Draws a pill-style select with rounded edges. */
|
|
181
|
-
@property({
|
|
184
|
+
@property({type: Boolean, reflect: true}) pill = false;
|
|
182
185
|
|
|
183
186
|
/** The select's label. If you need to display HTML, use the `label` slot instead. */
|
|
184
187
|
@property() label = '';
|
|
185
188
|
|
|
186
189
|
/** Text that appears in a tooltip next to the label. If you need to display HTML in the tooltip, use the `label-tooltip` slot instead. */
|
|
187
|
-
@property({
|
|
190
|
+
@property({attribute: 'label-tooltip'}) labelTooltip = '';
|
|
188
191
|
|
|
189
192
|
/** Text that appears above the input, on the right, to add additional context. If you need to display HTML in this text, use the `context-note` slot instead. */
|
|
190
|
-
@property({
|
|
193
|
+
@property({attribute: 'context-note'}) contextNote = '';
|
|
191
194
|
|
|
192
195
|
/**
|
|
193
196
|
* The preferred placement of the selects menu. Note that the actual placement may vary as needed to keep the listbox
|
|
194
197
|
* inside the viewport.
|
|
195
198
|
*/
|
|
196
|
-
@property({
|
|
199
|
+
@property({reflect: true}) placement: 'top' | 'bottom' = 'bottom';
|
|
197
200
|
|
|
198
201
|
/** The select's help text. If you need to display HTML, use the `help-text` slot instead. */
|
|
199
|
-
@property({
|
|
202
|
+
@property({attribute: 'help-text'}) helpText = '';
|
|
200
203
|
|
|
201
204
|
/**
|
|
202
205
|
* By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you
|
|
203
206
|
* to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
|
|
204
207
|
* the same document or shadow root for this to work.
|
|
205
208
|
*/
|
|
206
|
-
@property({
|
|
209
|
+
@property({reflect: true}) form: string;
|
|
207
210
|
|
|
208
211
|
/** The select's required attribute. */
|
|
209
|
-
@property({
|
|
212
|
+
@property({type: Boolean, reflect: true}) required = false;
|
|
210
213
|
|
|
211
|
-
@property({
|
|
214
|
+
@property({attribute: 'cache-key'}) cacheKey: string = "";
|
|
215
|
+
|
|
216
|
+
@property({type: Boolean, attribute: 'trigger-submit'}) triggerSubmit = false;
|
|
212
217
|
|
|
213
218
|
/**
|
|
214
219
|
* A function that customizes the tags to be rendered when multiple=true. The first argument is the option, the second
|
|
@@ -266,6 +271,15 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
266
271
|
}
|
|
267
272
|
}
|
|
268
273
|
|
|
274
|
+
private updateHasCheckboxPrefix() {
|
|
275
|
+
try {
|
|
276
|
+
const assigned = this.prefixSlot?.assignedElements({flatten: true}) || [];
|
|
277
|
+
this.hasCheckboxPrefix = assigned.some(el => el.tagName === 'ZN-CHECKBOX');
|
|
278
|
+
} catch {
|
|
279
|
+
this.hasCheckboxPrefix = false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
269
283
|
private addOpenListeners() {
|
|
270
284
|
const root = this.getRootNode();
|
|
271
285
|
root.addEventListener('focusin', this.handleDocumentFocusIn);
|
|
@@ -278,7 +292,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
278
292
|
this.closeWatcher.onclose = () => {
|
|
279
293
|
if (this.open) {
|
|
280
294
|
this.hide();
|
|
281
|
-
this.displayInput.focus({
|
|
295
|
+
this.displayInput.focus({preventScroll: true});
|
|
282
296
|
}
|
|
283
297
|
};
|
|
284
298
|
}
|
|
@@ -330,7 +344,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
330
344
|
event.preventDefault();
|
|
331
345
|
event.stopPropagation();
|
|
332
346
|
this.hide();
|
|
333
|
-
this.displayInput.focus({
|
|
347
|
+
this.displayInput.focus({preventScroll: true});
|
|
334
348
|
}
|
|
335
349
|
|
|
336
350
|
// Handle enter and space. When pressing space, we allow for type to select behaviors so if there's anything in the
|
|
@@ -362,7 +376,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
362
376
|
|
|
363
377
|
if (!this.multiple) {
|
|
364
378
|
this.hide();
|
|
365
|
-
this.displayInput.focus({
|
|
379
|
+
this.displayInput.focus({preventScroll: true});
|
|
366
380
|
}
|
|
367
381
|
}
|
|
368
382
|
|
|
@@ -463,13 +477,15 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
463
477
|
|
|
464
478
|
// not the keyboard_arrow_down icon
|
|
465
479
|
const isExpandIcon = path.some(el => el instanceof Element && el.classList.contains('select__expand-icon'));
|
|
480
|
+
// if click is inside the prefix area (e.g. checkbox), don't toggle the select
|
|
481
|
+
const inPrefix = path.some(el => el instanceof Element && el.classList.contains('select__prefix'));
|
|
466
482
|
// Ignore disabled controls and clicks on tags (remove buttons)
|
|
467
|
-
if ((this.disabled || isIcon) && !isExpandIcon) {
|
|
483
|
+
if (((this.disabled || isIcon) && !isExpandIcon) || inPrefix) {
|
|
468
484
|
return;
|
|
469
485
|
}
|
|
470
486
|
|
|
471
487
|
event.preventDefault();
|
|
472
|
-
this.displayInput.focus({
|
|
488
|
+
this.displayInput.focus({preventScroll: true});
|
|
473
489
|
this.open = !this.open;
|
|
474
490
|
}
|
|
475
491
|
|
|
@@ -478,8 +494,14 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
478
494
|
return;
|
|
479
495
|
}
|
|
480
496
|
|
|
481
|
-
|
|
482
|
-
|
|
497
|
+
// If keydown originated from within the prefix (e.g. checkbox)
|
|
498
|
+
const path = event.composedPath();
|
|
499
|
+
const inPrefix = path.some(el => el instanceof Element && (el as Element).classList?.contains('select__prefix'));
|
|
500
|
+
|
|
501
|
+
if (!inPrefix) {
|
|
502
|
+
event.stopPropagation();
|
|
503
|
+
this.handleDocumentKeyDown(event);
|
|
504
|
+
}
|
|
483
505
|
}
|
|
484
506
|
|
|
485
507
|
private handleClearClick(event: MouseEvent) {
|
|
@@ -487,7 +509,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
487
509
|
|
|
488
510
|
if (this.value !== '') {
|
|
489
511
|
this.setSelectedOptions([]);
|
|
490
|
-
this.displayInput.focus({
|
|
512
|
+
this.displayInput.focus({preventScroll: true});
|
|
491
513
|
|
|
492
514
|
// Emit after update
|
|
493
515
|
this.updateComplete.then(() => {
|
|
@@ -526,7 +548,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
526
548
|
}
|
|
527
549
|
|
|
528
550
|
// Set focus after updating so the value is announced by screen readers
|
|
529
|
-
this.updateComplete.then(() => this.displayInput.focus({
|
|
551
|
+
this.updateComplete.then(() => this.displayInput.focus({preventScroll: true}));
|
|
530
552
|
|
|
531
553
|
if (this.value !== oldValue) {
|
|
532
554
|
// Emit after updating
|
|
@@ -538,7 +560,11 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
538
560
|
|
|
539
561
|
if (!this.multiple) {
|
|
540
562
|
this.hide();
|
|
541
|
-
this.displayInput.focus({
|
|
563
|
+
this.displayInput.focus({preventScroll: true});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (this.triggerSubmit) {
|
|
567
|
+
this.formControlController.submit();
|
|
542
568
|
}
|
|
543
569
|
}
|
|
544
570
|
}
|
|
@@ -745,9 +771,11 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
745
771
|
conditionalSelect.dispatchEvent(new Event('zn-input'));
|
|
746
772
|
});
|
|
747
773
|
}
|
|
774
|
+
|
|
775
|
+
this.updateHasCheckboxPrefix();
|
|
748
776
|
}
|
|
749
777
|
|
|
750
|
-
@watch('disabled', {
|
|
778
|
+
@watch('disabled', {waitUntilFirstUpdate: true})
|
|
751
779
|
handleDisabledChange() {
|
|
752
780
|
// Close the listbox when the control is disabled
|
|
753
781
|
if (this.disabled) {
|
|
@@ -768,7 +796,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
768
796
|
}
|
|
769
797
|
}
|
|
770
798
|
|
|
771
|
-
@watch(['defaultValue', 'value'], {
|
|
799
|
+
@watch(['defaultValue', 'value'], {waitUntilFirstUpdate: true})
|
|
772
800
|
handleValueChange() {
|
|
773
801
|
if (!this.valueHasChanged) {
|
|
774
802
|
const cachedValueHasChanged = this.valueHasChanged;
|
|
@@ -784,7 +812,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
784
812
|
this.setSelectedOptions(allOptions.filter(el => value.includes(el.value)));
|
|
785
813
|
}
|
|
786
814
|
|
|
787
|
-
@watch('open', {
|
|
815
|
+
@watch('open', {waitUntilFirstUpdate: true})
|
|
788
816
|
async handleOpenChange() {
|
|
789
817
|
if (this.open && !this.disabled) {
|
|
790
818
|
// Reset the current option
|
|
@@ -803,7 +831,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
803
831
|
this.setCurrentOption(this.currentOption);
|
|
804
832
|
});
|
|
805
833
|
|
|
806
|
-
const {
|
|
834
|
+
const {keyframes, options} = getAnimation(this, 'select.show', {dir: this.localize.dir()});
|
|
807
835
|
await animateTo(this.popup.popup, keyframes, options);
|
|
808
836
|
|
|
809
837
|
// Make sure the current option is scrolled into view (required for Safari)
|
|
@@ -818,7 +846,7 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
818
846
|
this.removeOpenListeners();
|
|
819
847
|
|
|
820
848
|
await stopAnimations(this);
|
|
821
|
-
const {
|
|
849
|
+
const {keyframes, options} = getAnimation(this, 'select.hide', {dir: this.localize.dir()});
|
|
822
850
|
await animateTo(this.popup.popup, keyframes, options);
|
|
823
851
|
this.listbox.hidden = true;
|
|
824
852
|
this.popup.active = false;
|
|
@@ -942,7 +970,8 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
942
970
|
'select--bottom': this.placement === 'bottom',
|
|
943
971
|
'select--small': this.size === 'small',
|
|
944
972
|
'select--medium': this.size === 'medium',
|
|
945
|
-
'select--large': this.size === 'large'
|
|
973
|
+
'select--large': this.size === 'large',
|
|
974
|
+
'select--has-checkbox-prefix': this.hasCheckboxPrefix
|
|
946
975
|
})}
|
|
947
976
|
placement=${this.placement}
|
|
948
977
|
strategy=${this.hoist ? 'fixed' : 'absolute'}
|
|
@@ -957,7 +986,10 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
957
986
|
slot="anchor"
|
|
958
987
|
@keydown=${this.handleComboboxKeyDown}
|
|
959
988
|
@mousedown=${this.handleComboboxMouseDown}>
|
|
960
|
-
<slot part="prefix"
|
|
989
|
+
<slot part="prefix"
|
|
990
|
+
name="prefix"
|
|
991
|
+
class="select__prefix"
|
|
992
|
+
@slotchange=${() => this.updateHasCheckboxPrefix()}></slot>
|
|
961
993
|
|
|
962
994
|
<input
|
|
963
995
|
part="display-input"
|
|
@@ -1049,16 +1081,16 @@ export default class ZnSelect extends ZincElement implements ZincFormControl {
|
|
|
1049
1081
|
|
|
1050
1082
|
setDefaultAnimation('select.show', {
|
|
1051
1083
|
keyframes: [
|
|
1052
|
-
{
|
|
1053
|
-
{
|
|
1084
|
+
{opacity: 0, scale: 0.9},
|
|
1085
|
+
{opacity: 1, scale: 1}
|
|
1054
1086
|
],
|
|
1055
|
-
options: {
|
|
1087
|
+
options: {duration: 100, easing: 'ease'}
|
|
1056
1088
|
});
|
|
1057
1089
|
|
|
1058
1090
|
setDefaultAnimation('select.hide', {
|
|
1059
1091
|
keyframes: [
|
|
1060
|
-
{
|
|
1061
|
-
{
|
|
1092
|
+
{opacity: 1, scale: 1},
|
|
1093
|
+
{opacity: 0, scale: 0.9}
|
|
1062
1094
|
],
|
|
1063
|
-
options: {
|
|
1095
|
+
options: {duration: 100, easing: 'ease'}
|
|
1064
1096
|
});
|
|
@@ -48,6 +48,14 @@
|
|
|
48
48
|
var(--zn-transition-fast) background-color;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/* Prefix area: allow a leading control (e.g., checkbox) full-height */
|
|
52
|
+
.select__prefix {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
align-self: stretch;
|
|
56
|
+
height: 100%;
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
.select__display-input {
|
|
52
60
|
position: relative;
|
|
53
61
|
width: 100%;
|
|
@@ -175,6 +183,10 @@
|
|
|
175
183
|
padding-inline: var(--zn-input-spacing-medium);
|
|
176
184
|
}
|
|
177
185
|
|
|
186
|
+
.select--has-checkbox-prefix.select--medium .select__combobox {
|
|
187
|
+
padding-inline-start: 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
178
190
|
.select--medium .select__clear {
|
|
179
191
|
margin-inline-start: var(--zn-input-spacing-medium);
|
|
180
192
|
}
|
|
@@ -200,6 +212,10 @@
|
|
|
200
212
|
padding-inline: var(--zn-input-spacing-large);
|
|
201
213
|
}
|
|
202
214
|
|
|
215
|
+
.select--has-checkbox-prefix.select--large .select__combobox {
|
|
216
|
+
padding-inline-start: 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
203
219
|
.select--large .select__clear {
|
|
204
220
|
margin-inline-start: var(--zn-input-spacing-large);
|
|
205
221
|
}
|
|
@@ -241,6 +257,11 @@
|
|
|
241
257
|
color: var(--zn-input-icon-color);
|
|
242
258
|
}
|
|
243
259
|
|
|
260
|
+
/* When a checkbox is used in the prefix, remove left padding so the prefix joins flush */
|
|
261
|
+
.select--has-checkbox-prefix.select--standard .select__combobox {
|
|
262
|
+
padding-inline-start: 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
244
265
|
/* Clear button */
|
|
245
266
|
.select__clear {
|
|
246
267
|
display: inline-flex;
|