@ekzo-dev/bootstrap-addons 5.2.24 → 5.2.25
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekzo-dev/bootstrap-addons",
|
|
3
3
|
"description": "Aurelia Bootstrap additional component",
|
|
4
|
-
"version": "5.2.
|
|
4
|
+
"version": "5.2.25",
|
|
5
5
|
"homepage": "https://github.com/ekzo-dev/aurelia-components/tree/main/packages/bootstrap-addons",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@ekzo-dev/bootstrap": "^5.2.
|
|
12
|
+
"@ekzo-dev/bootstrap": "^5.2.19",
|
|
13
13
|
"@ekzo-dev/vanilla-jsoneditor": "^0.23.7",
|
|
14
14
|
"@ekzo-dev/toolkit": "^1.2.4",
|
|
15
15
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
|
@@ -5,11 +5,13 @@ import { valueConverter } from 'aurelia';
|
|
|
5
5
|
export class Filter {
|
|
6
6
|
toView(
|
|
7
7
|
list: Map<string, ISelectOption[]> | ISelectOption[],
|
|
8
|
-
search: string
|
|
8
|
+
search: string,
|
|
9
|
+
emptyOption?: ISelectOption
|
|
9
10
|
): Map<string, ISelectOption[]> | ISelectOption[] {
|
|
10
|
-
if (search === '') return list;
|
|
11
|
+
if (search === '' && emptyOption === undefined) return list;
|
|
11
12
|
|
|
12
|
-
const cb = (option:
|
|
13
|
+
const cb = (option: ISelectOption) =>
|
|
14
|
+
option.value !== emptyOption?.value && option.text.toLowerCase().includes(search.toLowerCase());
|
|
13
15
|
|
|
14
16
|
if (list instanceof Map) {
|
|
15
17
|
const result = new Map<string, ISelectOption[]>();
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
id.bind="id"
|
|
29
29
|
class="form-select ${bsSize ? `form-select-${bsSize}` : ''} ${valid ? 'is-valid' : valid === false ? 'is-invalid' : ''}"
|
|
30
30
|
bs-dropdown-toggle="arrow.bind: false"
|
|
31
|
-
value="${
|
|
31
|
+
value="${valueText}"
|
|
32
|
+
placeholder="${emptyOption?.text ?? ''}"
|
|
32
33
|
disabled.bind="disabled"
|
|
33
34
|
required.bind="required"
|
|
34
35
|
form.bind="form & attr"
|
|
@@ -38,6 +39,12 @@
|
|
|
38
39
|
keydown.trigger="$event.preventDefault()"
|
|
39
40
|
ref="control"
|
|
40
41
|
/>
|
|
42
|
+
<button
|
|
43
|
+
if.bind="emptyOption && selectedOption?.value !== emptyOption?.value"
|
|
44
|
+
bs-close-button
|
|
45
|
+
type="button"
|
|
46
|
+
click.trigger="selectOption(emptyOption)"
|
|
47
|
+
></button>
|
|
41
48
|
<bs-dropdown-menu>
|
|
42
49
|
<div bs-dropdown-item="text" if.bind="optionsCount > 10">
|
|
43
50
|
<input class="form-control" placeholder="Filter options" type="search" value.bind="filter & debounce:250" />
|
|
@@ -45,19 +52,19 @@
|
|
|
45
52
|
<hr bs-dropdown-item="divider" if.bind="optionsCount > 10" />
|
|
46
53
|
<button
|
|
47
54
|
type="button"
|
|
48
|
-
repeat.for="option of ungroupedOptions | filter:filter"
|
|
49
|
-
bs-dropdown-item="active.bind: option.value === selectedOption
|
|
55
|
+
repeat.for="option of ungroupedOptions | filter:filter:emptyOption"
|
|
56
|
+
bs-dropdown-item="active.bind: option.value === selectedOption?.value; disabled.bind: option.disabled"
|
|
50
57
|
click.trigger="selectOption(option)"
|
|
51
58
|
>
|
|
52
59
|
${option.text || ' '}
|
|
53
60
|
</button>
|
|
54
|
-
<template repeat.for="[k, v] of groupedOptions | filter:filter">
|
|
61
|
+
<template repeat.for="[k, v] of groupedOptions | filter:filter:emptyOption">
|
|
55
62
|
<h6 bs-dropdown-item="header">${k}</h6>
|
|
56
63
|
<button
|
|
57
64
|
class="ps-4"
|
|
58
65
|
type="button"
|
|
59
66
|
repeat.for="option of v"
|
|
60
|
-
bs-dropdown-item="active.bind: option.value === selectedOption
|
|
67
|
+
bs-dropdown-item="active.bind: option.value === selectedOption?.value; disabled.bind: option.disabled"
|
|
61
68
|
click.trigger="selectOption(option)"
|
|
62
69
|
>
|
|
63
70
|
${option.text || ' '}
|
|
@@ -1,17 +1,40 @@
|
|
|
1
|
-
@import '
|
|
2
|
-
@import '
|
|
3
|
-
@import '
|
|
4
|
-
@import '
|
|
5
|
-
@import '
|
|
6
|
-
@import '~bootstrap/scss/forms/form-check';
|
|
1
|
+
@import 'bootstrap/scss/functions';
|
|
2
|
+
@import 'bootstrap/scss/variables';
|
|
3
|
+
@import 'bootstrap/scss/maps';
|
|
4
|
+
@import 'bootstrap/scss/mixins';
|
|
5
|
+
@import 'bootstrap/scss/forms/form-check';
|
|
7
6
|
|
|
8
7
|
bs-select {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
> .form-select {
|
|
8
|
+
.form-select {
|
|
12
9
|
cursor: default;
|
|
13
10
|
}
|
|
14
11
|
|
|
12
|
+
&:has(.btn-close) .form-select {
|
|
13
|
+
padding-right: 4rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.btn-close {
|
|
17
|
+
display: block;
|
|
18
|
+
position: relative;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
width: 0.8rem;
|
|
21
|
+
height: 0.8rem;
|
|
22
|
+
top: calc(-1px - 1.5rem);
|
|
23
|
+
left: calc(100% - 3.25rem);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.form-select-lg + .btn-close {
|
|
27
|
+
top: calc(-1px - 1.8rem);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.form-select-sm + .btn-close {
|
|
31
|
+
top: calc(-1px - 1.3rem);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&.form-floating .btn-close {
|
|
35
|
+
top: calc(-1px - 2.15rem) !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
.dropdown-menu {
|
|
16
39
|
width: max-content;
|
|
17
40
|
min-width: 100%;
|
|
@@ -76,3 +99,16 @@ bs-select {
|
|
|
76
99
|
}
|
|
77
100
|
}
|
|
78
101
|
}
|
|
102
|
+
|
|
103
|
+
/* stylelint-disable */
|
|
104
|
+
.was-validated bs-select:has(.btn-close) .form-select:invalid,
|
|
105
|
+
.was-validated bs-select:has(.btn-close) .form-select:valid,
|
|
106
|
+
bs-select:has(.btn-close) .form-select.is-invalid,
|
|
107
|
+
bs-select:has(.btn-close) .form-select.is-valid {
|
|
108
|
+
padding-right: 5.5rem !important;
|
|
109
|
+
|
|
110
|
+
+ .btn-close {
|
|
111
|
+
left: calc(100% - 4.75rem);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/* stylelint-enable */
|
|
@@ -15,12 +15,14 @@ export default {
|
|
|
15
15
|
args: {
|
|
16
16
|
label: 'Label',
|
|
17
17
|
options: [
|
|
18
|
-
{ value: undefined, text: '' },
|
|
18
|
+
{ value: undefined, text: 'Select option' },
|
|
19
19
|
{ value: '1', text: 'One', disabled: true },
|
|
20
20
|
{ value: '2', text: 'Two' },
|
|
21
21
|
{ value: '3', text: 'Three', group: 'Group' },
|
|
22
22
|
],
|
|
23
23
|
value: '2',
|
|
24
|
+
floatingLabel: false,
|
|
25
|
+
valid: null,
|
|
24
26
|
},
|
|
25
27
|
argTypes: {
|
|
26
28
|
bsSize: {
|
|
@@ -3,6 +3,7 @@ import template from './select.html';
|
|
|
3
3
|
import './select.scss';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
BsCloseButton,
|
|
6
7
|
BsDropdown,
|
|
7
8
|
BsDropdownItem,
|
|
8
9
|
BsDropdownMenu,
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
BsSelect as BaseBsSelect,
|
|
11
12
|
ISelectOption,
|
|
12
13
|
} from '@ekzo-dev/bootstrap';
|
|
13
|
-
import { customElement, ICustomElementViewModel } from 'aurelia';
|
|
14
|
+
import { bindable, customElement, ICustomElementViewModel } from 'aurelia';
|
|
14
15
|
|
|
15
16
|
import { Filter } from './filter';
|
|
16
17
|
|
|
@@ -22,9 +23,12 @@ const BS_SIZE_MULTIPLIER = {
|
|
|
22
23
|
@customElement({
|
|
23
24
|
name: 'bs-select',
|
|
24
25
|
template,
|
|
25
|
-
dependencies: [BsDropdown, BsDropdownMenu, BsDropdownToggle, BsDropdownItem, Filter],
|
|
26
|
+
dependencies: [BsDropdown, BsDropdownMenu, BsDropdownToggle, BsDropdownItem, Filter, BsCloseButton],
|
|
26
27
|
})
|
|
27
28
|
export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
29
|
+
@bindable()
|
|
30
|
+
emptyValue?: unknown = null;
|
|
31
|
+
|
|
28
32
|
control!: HTMLFieldSetElement;
|
|
29
33
|
|
|
30
34
|
filter: string = '';
|
|
@@ -33,6 +37,8 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
|
33
37
|
|
|
34
38
|
deactivating: boolean = false;
|
|
35
39
|
|
|
40
|
+
emptyOption?: ISelectOption;
|
|
41
|
+
|
|
36
42
|
binding() {
|
|
37
43
|
super.binding();
|
|
38
44
|
this.deactivating = false;
|
|
@@ -67,6 +73,14 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
|
67
73
|
this.#dispatchEvents();
|
|
68
74
|
}
|
|
69
75
|
|
|
76
|
+
get valueText(): string {
|
|
77
|
+
const { selectedOption, emptyOption } = this;
|
|
78
|
+
|
|
79
|
+
return emptyOption && emptyOption.value === selectedOption?.value
|
|
80
|
+
? ''
|
|
81
|
+
: `${selectedOption?.group ? selectedOption.group + ' / ' : ''}${selectedOption?.text ?? ''}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
70
84
|
#dispatchEvents() {
|
|
71
85
|
const change = new Event('change', { bubbles: true });
|
|
72
86
|
const input = new Event('input', { bubbles: true });
|
|
@@ -102,8 +116,9 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
|
102
116
|
get selectedOption(): ISelectOption | undefined {
|
|
103
117
|
if (this['__raw__'].deactivating) return;
|
|
104
118
|
|
|
105
|
-
const { matcher, value } = this;
|
|
119
|
+
const { matcher, value, emptyValue } = this;
|
|
106
120
|
let { options } = this;
|
|
121
|
+
let emptyOption: ISelectOption;
|
|
107
122
|
|
|
108
123
|
if (options instanceof Object && options.constructor === Object) {
|
|
109
124
|
options = Object.entries(options);
|
|
@@ -115,12 +130,19 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
|
115
130
|
let option = (options as Array<ISelectOption | readonly [unknown, string]>).find((option) => {
|
|
116
131
|
const currentValue: unknown = isEntries ? option[0] : (option as ISelectOption).value;
|
|
117
132
|
|
|
133
|
+
if (currentValue == emptyValue) {
|
|
134
|
+
emptyOption = {
|
|
135
|
+
value: currentValue,
|
|
136
|
+
text: isEntries ? option[1] : (option as ISelectOption).text,
|
|
137
|
+
} as ISelectOption;
|
|
138
|
+
}
|
|
139
|
+
|
|
118
140
|
return matcher ? matcher(value, currentValue) : value === currentValue;
|
|
119
141
|
});
|
|
120
142
|
|
|
121
143
|
option = isEntries && option !== undefined ? { value: option[0], text: option[1] } : (option as ISelectOption);
|
|
122
144
|
|
|
123
|
-
// update value next tick
|
|
145
|
+
// update value next tick
|
|
124
146
|
const foundValue = option?.value;
|
|
125
147
|
|
|
126
148
|
if (foundValue !== value) {
|
|
@@ -128,6 +150,9 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
|
|
|
128
150
|
void Promise.resolve().then(() => (this.value = foundValue));
|
|
129
151
|
}
|
|
130
152
|
|
|
153
|
+
// update empty option next tick
|
|
154
|
+
void Promise.resolve().then(() => (this.emptyOption = emptyOption));
|
|
155
|
+
|
|
131
156
|
return option;
|
|
132
157
|
}
|
|
133
158
|
}
|