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.
Files changed (43) hide show
  1. package/dist/selectic.common.js +545 -67
  2. package/dist/selectic.esm.js +546 -69
  3. package/doc/changeIcons.md +118 -0
  4. package/doc/changeText.md +1 -1
  5. package/doc/domProperties.md +57 -19
  6. package/doc/extendedProperties.md +83 -72
  7. package/doc/main.md +2 -0
  8. package/doc/params.md +177 -112
  9. package/doc/properties.md +42 -0
  10. package/package.json +4 -4
  11. package/src/ExtendedList.tsx +53 -6
  12. package/src/Filter.tsx +11 -9
  13. package/src/Icon.tsx +199 -0
  14. package/src/List.tsx +12 -6
  15. package/src/MainInput.tsx +15 -11
  16. package/src/Store.tsx +290 -123
  17. package/src/css/selectic.css +24 -0
  18. package/src/icons/caret-down.tsx +21 -0
  19. package/src/icons/caret-up.tsx +21 -0
  20. package/src/icons/check.tsx +23 -0
  21. package/src/icons/question.tsx +21 -0
  22. package/src/icons/search.tsx +21 -0
  23. package/src/icons/spinner.tsx +21 -0
  24. package/src/icons/strikeThrough.tsx +21 -0
  25. package/src/icons/times.tsx +21 -0
  26. package/src/index.tsx +78 -37
  27. package/test/Store/Store_computed.spec.js +84 -0
  28. package/test/Store/changeIcons.spec.js +154 -0
  29. package/test/Store/selectGroup.spec.js +389 -0
  30. package/test/Store/selectItem.spec.js +100 -46
  31. package/test/helper.js +38 -34
  32. package/types/ExtendedList.d.ts +7 -2
  33. package/types/Icon.d.ts +25 -0
  34. package/types/Store.d.ts +142 -5
  35. package/types/icons/caret-down.d.ts +6 -0
  36. package/types/icons/caret-up.d.ts +6 -0
  37. package/types/icons/check.d.ts +6 -0
  38. package/types/icons/question.d.ts +6 -0
  39. package/types/icons/search.d.ts +6 -0
  40. package/types/icons/spinner.d.ts +6 -0
  41. package/types/icons/strikeThrough.d.ts +6 -0
  42. package/types/icons/times.d.ts +6 -0
  43. 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: 'fa fa-spinner fa-spin',
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 || option.isGroup) {
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
- <span
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
- <span class={option.icon}></span>
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
- <span
383
- class="fa fa-strikethrough selectic-input__reverse-icon"
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
- <span
404
- class="fa fa-times selectic-input__selected-items__icon"
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
- ></span>
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
- <span
425
- class="fa fa-times selectic-input__clear-icon"
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
- ></span>
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
- <span
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
  );