selectic 3.0.21 → 3.1.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/dist/selectic.common.js +545 -67
- package/dist/selectic.esm.js +546 -69
- package/doc/changeIcons.md +118 -0
- package/doc/changeText.md +1 -1
- package/doc/domProperties.md +57 -19
- package/doc/extendedProperties.md +83 -72
- package/doc/main.md +2 -0
- package/doc/params.md +177 -112
- package/doc/properties.md +42 -0
- package/package.json +4 -4
- package/src/ExtendedList.tsx +53 -6
- package/src/Filter.tsx +11 -9
- package/src/Icon.tsx +199 -0
- package/src/List.tsx +12 -6
- package/src/MainInput.tsx +15 -11
- package/src/Store.tsx +290 -123
- package/src/css/selectic.css +24 -0
- package/src/icons/caret-down.tsx +21 -0
- package/src/icons/caret-up.tsx +21 -0
- package/src/icons/check.tsx +23 -0
- package/src/icons/question.tsx +21 -0
- package/src/icons/search.tsx +21 -0
- package/src/icons/spinner.tsx +21 -0
- package/src/icons/strikeThrough.tsx +21 -0
- package/src/icons/times.tsx +21 -0
- package/src/index.tsx +78 -37
- package/test/Store/Store_computed.spec.js +84 -0
- package/test/Store/changeIcons.spec.js +154 -0
- package/test/Store/selectGroup.spec.js +389 -0
- package/test/Store/selectItem.spec.js +100 -46
- package/test/helper.js +38 -34
- package/types/ExtendedList.d.ts +7 -2
- package/types/Icon.d.ts +25 -0
- package/types/Store.d.ts +142 -5
- package/types/icons/caret-down.d.ts +6 -0
- package/types/icons/caret-up.d.ts +6 -0
- package/types/icons/check.d.ts +6 -0
- package/types/icons/question.d.ts +6 -0
- package/types/icons/search.d.ts +6 -0
- package/types/icons/spinner.d.ts +6 -0
- package/types/icons/strikeThrough.d.ts +6 -0
- package/types/icons/times.d.ts +6 -0
- package/types/index.d.ts +74 -1
package/src/Icon.tsx
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* File Purpose:
|
|
2
|
+
* Display the wanted icon.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component, h, Prop, Vue, Watch } from 'vtyx';
|
|
6
|
+
|
|
7
|
+
import Store, { IconFamily, IconKey, IconValue } from './Store';
|
|
8
|
+
import IconCaretDown from './icons/caret-down';
|
|
9
|
+
import IconCaretUp from './icons/caret-up';
|
|
10
|
+
import IconCheck from './icons/check';
|
|
11
|
+
import IconQuestion from './icons/question';
|
|
12
|
+
import IconSearch from './icons/search';
|
|
13
|
+
import IconSpinner from './icons/spinner';
|
|
14
|
+
import IconStrikeThrough from './icons/strikeThrough';
|
|
15
|
+
import IconTimes from './icons/times';
|
|
16
|
+
|
|
17
|
+
export interface Props {
|
|
18
|
+
store: Store;
|
|
19
|
+
icon: string;
|
|
20
|
+
spin?: boolean;
|
|
21
|
+
title?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Component
|
|
25
|
+
export default class Icon extends Vue<Props> {
|
|
26
|
+
|
|
27
|
+
/* {{{ props */
|
|
28
|
+
|
|
29
|
+
@Prop()
|
|
30
|
+
private store: Store;
|
|
31
|
+
|
|
32
|
+
@Prop()
|
|
33
|
+
private icon: IconKey;
|
|
34
|
+
|
|
35
|
+
@Prop()
|
|
36
|
+
private spin?: boolean;
|
|
37
|
+
|
|
38
|
+
@Prop()
|
|
39
|
+
private title?: string;
|
|
40
|
+
|
|
41
|
+
/* }}} */
|
|
42
|
+
/* {{{ computed */
|
|
43
|
+
|
|
44
|
+
private get rawIconValue(): IconValue {
|
|
45
|
+
const key = this.icon;
|
|
46
|
+
const icon = this.store.data.icons[key];
|
|
47
|
+
|
|
48
|
+
if (icon === undefined) {
|
|
49
|
+
return key;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return icon;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private get family(): IconFamily {
|
|
56
|
+
const iconValue = this.rawIconValue;
|
|
57
|
+
|
|
58
|
+
if (iconValue.startsWith('selectic:')) {
|
|
59
|
+
return 'selectic';
|
|
60
|
+
}
|
|
61
|
+
if (iconValue.startsWith('raw:')) {
|
|
62
|
+
return 'raw';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this.store.data.iconFamily;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private get iconValue(): string {
|
|
69
|
+
const key = this.rawIconValue;
|
|
70
|
+
|
|
71
|
+
if (key.includes(':')) {
|
|
72
|
+
/* This is to retrieve value from string such as
|
|
73
|
+
* 'selectic:spinner:spin' (and get only 'spinner') */
|
|
74
|
+
const value = key.split(':');
|
|
75
|
+
|
|
76
|
+
return value[1];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return key;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private get vueIcon() {
|
|
83
|
+
switch(this.icon) {
|
|
84
|
+
case 'caret-down':
|
|
85
|
+
return IconCaretDown;
|
|
86
|
+
case 'caret-up':
|
|
87
|
+
return IconCaretUp;
|
|
88
|
+
case 'check':
|
|
89
|
+
return IconCheck;
|
|
90
|
+
case 'search':
|
|
91
|
+
return IconSearch;
|
|
92
|
+
case 'spinner':
|
|
93
|
+
return IconSpinner;
|
|
94
|
+
case 'strikethrough':
|
|
95
|
+
return IconStrikeThrough;
|
|
96
|
+
case 'times':
|
|
97
|
+
return IconTimes;
|
|
98
|
+
case 'question':
|
|
99
|
+
default:
|
|
100
|
+
return IconQuestion;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private get spinClass(): string {
|
|
105
|
+
let value = this.store.data.icons.spin;
|
|
106
|
+
|
|
107
|
+
if (typeof value === 'string') {
|
|
108
|
+
if (value.startsWith('selectic:')) {
|
|
109
|
+
return 'selectic-spin';
|
|
110
|
+
}
|
|
111
|
+
if (value.includes(':')) {
|
|
112
|
+
value = value.split(':')[1] ?? 'spin';
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
value = 'spin';
|
|
116
|
+
}
|
|
117
|
+
const family = this.family;
|
|
118
|
+
|
|
119
|
+
let prefix = '';
|
|
120
|
+
|
|
121
|
+
switch (family) {
|
|
122
|
+
case 'font-awesome-4':
|
|
123
|
+
prefix = 'fa-';
|
|
124
|
+
break;
|
|
125
|
+
case 'font-awesome-5':
|
|
126
|
+
prefix = 'fa-';
|
|
127
|
+
break;
|
|
128
|
+
case 'font-awesome-6':
|
|
129
|
+
prefix = 'fa-';
|
|
130
|
+
break;
|
|
131
|
+
case '':
|
|
132
|
+
case 'selectic':
|
|
133
|
+
prefix = 'selectic-';
|
|
134
|
+
break;
|
|
135
|
+
case 'raw':
|
|
136
|
+
prefix = '';
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
prefix = 'selectic-';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return `${prefix}${value}`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private get spinActive(): boolean {
|
|
146
|
+
return this.spin || this.rawIconValue.endsWith(':spin');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* }}} */
|
|
150
|
+
|
|
151
|
+
private renderInnerIcon() {
|
|
152
|
+
const component = this.vueIcon;
|
|
153
|
+
|
|
154
|
+
return h(
|
|
155
|
+
component,
|
|
156
|
+
{
|
|
157
|
+
class: {
|
|
158
|
+
'selectic__icon': true,
|
|
159
|
+
[this.spinClass]: this.spinActive,
|
|
160
|
+
},
|
|
161
|
+
title: this.title,
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private renderSpanIcon(prefix: string) {
|
|
167
|
+
const classSpin = this.spinActive && this.spinClass || '';
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<span
|
|
171
|
+
class={`${prefix}${this.iconValue} ${classSpin}`}
|
|
172
|
+
title={this.title}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public render() {
|
|
178
|
+
const family = this.family;
|
|
179
|
+
|
|
180
|
+
switch (family) {
|
|
181
|
+
case '':
|
|
182
|
+
case 'selectic':
|
|
183
|
+
return this.renderInnerIcon();
|
|
184
|
+
case 'font-awesome-4':
|
|
185
|
+
return this.renderSpanIcon('fa fa-fw fa-');
|
|
186
|
+
case 'font-awesome-5':
|
|
187
|
+
return this.renderSpanIcon('fas fa-fw fa-');
|
|
188
|
+
case 'font-awesome-4':
|
|
189
|
+
return this.renderSpanIcon('fa-solid fa-fw fa-');
|
|
190
|
+
case 'raw':
|
|
191
|
+
return this.renderSpanIcon('');
|
|
192
|
+
default:
|
|
193
|
+
if (family.startsWith('prefix:')) {
|
|
194
|
+
return this.renderSpanIcon(family.slice(7));
|
|
195
|
+
}
|
|
196
|
+
return this.renderInnerIcon();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
package/src/List.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import Store, {
|
|
|
10
10
|
OptionItem,
|
|
11
11
|
OptionId,
|
|
12
12
|
} from './Store';
|
|
13
|
+
import Icon from './Icon';
|
|
13
14
|
|
|
14
15
|
export interface Props {
|
|
15
16
|
store: Store;
|
|
@@ -71,7 +72,7 @@ export default class List extends Vue<Props> {
|
|
|
71
72
|
text: '',
|
|
72
73
|
disabled: true,
|
|
73
74
|
selected: false,
|
|
74
|
-
icon: '
|
|
75
|
+
icon: 'current:spinner:spin',
|
|
75
76
|
isGroup: false,
|
|
76
77
|
});
|
|
77
78
|
}
|
|
@@ -141,7 +142,11 @@ export default class List extends Vue<Props> {
|
|
|
141
142
|
/* {{{ methods */
|
|
142
143
|
|
|
143
144
|
private click(option: OptionItem) {
|
|
144
|
-
if (option.disabled
|
|
145
|
+
if (option.disabled) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (option.isGroup) {
|
|
149
|
+
this.store.selectGroup(option.id, !option.selected);
|
|
145
150
|
return;
|
|
146
151
|
}
|
|
147
152
|
|
|
@@ -265,6 +270,7 @@ export default class List extends Vue<Props> {
|
|
|
265
270
|
}}
|
|
266
271
|
class={['selectic-item', option.className || '', {
|
|
267
272
|
'selected': option.selected,
|
|
273
|
+
'selectable': unref(this.store.allowGroupSelection) && option.isGroup && !option.disabled,
|
|
268
274
|
'selectic-item__active': idx + this.startIndex === this.store.state.activeItemIdx,
|
|
269
275
|
'selectic-item__disabled': !!option.disabled,
|
|
270
276
|
'selectic-item__exclusive': !!option.exclusive,
|
|
@@ -276,12 +282,12 @@ export default class List extends Vue<Props> {
|
|
|
276
282
|
key={'selectic-item-' + (idx + this.startIndex)}
|
|
277
283
|
>
|
|
278
284
|
{this.isMultiple && (
|
|
279
|
-
<
|
|
280
|
-
class="fa fa-fw fa-check selectic-item_icon"
|
|
281
|
-
></span>
|
|
285
|
+
<Icon icon="check" store={this.store} class="selectic-item_icon" />
|
|
282
286
|
)}
|
|
283
287
|
{option.icon && (
|
|
284
|
-
|
|
288
|
+
option.icon.includes(':')
|
|
289
|
+
? <Icon icon={option.icon} store={this.store} />
|
|
290
|
+
: <Icon icon={`raw:${option.icon}`} store={this.store} />
|
|
285
291
|
)}
|
|
286
292
|
{option.text}
|
|
287
293
|
</li>
|
package/src/MainInput.tsx
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import {Vue, Component, Prop, Watch, h} from 'vtyx';
|
|
7
7
|
import Store, {OptionId, OptionItem} from './Store';
|
|
8
|
+
import Icon from './Icon';
|
|
8
9
|
|
|
9
10
|
export interface Props {
|
|
10
11
|
store: Store;
|
|
@@ -379,8 +380,9 @@ export default class MainInput extends Vue<Props> {
|
|
|
379
380
|
ref="selectedItems"
|
|
380
381
|
>
|
|
381
382
|
{this.isSelectionReversed && (
|
|
382
|
-
<
|
|
383
|
-
|
|
383
|
+
<Icon
|
|
384
|
+
icon="strikethrough"
|
|
385
|
+
store={this.store} class="selectic-input__reverse-icon"
|
|
384
386
|
title={this.reverseSelectionLabel}
|
|
385
387
|
/>
|
|
386
388
|
)}
|
|
@@ -400,12 +402,14 @@ export default class MainInput extends Vue<Props> {
|
|
|
400
402
|
{ item.text }
|
|
401
403
|
</span>
|
|
402
404
|
{!this.isDisabled && (
|
|
403
|
-
<
|
|
404
|
-
|
|
405
|
+
<Icon
|
|
406
|
+
icon="times"
|
|
407
|
+
class="selectic-input__selected-items__icon"
|
|
408
|
+
store={this.store}
|
|
405
409
|
on={{
|
|
406
410
|
'click.prevent.stop': () => this.selectItem(item.id),
|
|
407
411
|
}}
|
|
408
|
-
|
|
412
|
+
/>
|
|
409
413
|
)}
|
|
410
414
|
</div>
|
|
411
415
|
)
|
|
@@ -421,11 +425,13 @@ export default class MainInput extends Vue<Props> {
|
|
|
421
425
|
</div>
|
|
422
426
|
)}
|
|
423
427
|
{this.showClearAll && (
|
|
424
|
-
<
|
|
425
|
-
|
|
428
|
+
<Icon
|
|
429
|
+
icon="times"
|
|
430
|
+
class="selectic-input__clear-icon"
|
|
426
431
|
title={this.clearedLabel}
|
|
432
|
+
store={this.store}
|
|
427
433
|
on={{ 'click.prevent.stop': this.clearSelection }}
|
|
428
|
-
|
|
434
|
+
/>
|
|
429
435
|
)}
|
|
430
436
|
</div>
|
|
431
437
|
<div
|
|
@@ -438,9 +444,7 @@ export default class MainInput extends Vue<Props> {
|
|
|
438
444
|
'click.prevent.stop': () => this.toggleFocus(),
|
|
439
445
|
}}
|
|
440
446
|
>
|
|
441
|
-
<
|
|
442
|
-
class="fa fa-caret-down selectic-icon"
|
|
443
|
-
></span>
|
|
447
|
+
<Icon icon="caret-down" class="selectic-icon" store={this.store} />
|
|
444
448
|
</div>
|
|
445
449
|
</div>
|
|
446
450
|
);
|