@loop8/vue-select 0.1.3

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/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # Vue Loop8 Select
2
+
3
+ A Vue 3 select component inspired by Select2, built using the Composition API.
4
+
5
+ ## Features
6
+
7
+ - Single and multiple select support
8
+ - Search/filtering capabilities
9
+ - Remote data loading via AJAX
10
+ - Infinite scrolling pagination for large datasets
11
+ - Custom templates with slots for rich display options
12
+ - Keyboard navigation
13
+ - Customizable via props
14
+ - No jQuery dependency
15
+ - Form integration with standard HTML form elements
16
+ - Fully compatible with Vue 3 and the Composition API
17
+ - Works with v-model for two-way binding
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @loop8/vue-select
23
+ # or
24
+ yarn add @loop8/vue-select
25
+ ```
26
+
27
+ ## Importing Styles
28
+
29
+ After installing the package, you need to import the required CSS files in your main entry file (usually `main.js` or `main.ts`):
30
+
31
+ ```javascript
32
+ // Import the component styles
33
+ import '@loop8/vue-select/src/styles/loop-select.css';
34
+ import '@loop8/vue-select/src/styles/spinner.css';
35
+ ```
36
+
37
+ The styles are modular and can be customized by overriding the CSS classes. For complete styling documentation and available CSS classes, see the [Usage Guide](USAGE.md#customizing-appearance).
38
+
39
+ ## Styling and Customization
40
+
41
+ Loop8Select is designed to be easily customized:
42
+
43
+ - Uses global, non-scoped CSS classes that are simple to override
44
+ - Provides slots for custom option and selection templates
45
+ - Supports custom loading indicators
46
+ - Can be themed for light/dark modes or to match your application design by overriding CSS classes
47
+
48
+ ```vue
49
+ <!-- Basic usage -->
50
+ <Loop8Select
51
+ v-model="selected"
52
+ :options="options"
53
+ />
54
+ ```
55
+
56
+ For complete styling documentation and available CSS classes, see the [Usage Guide](USAGE.md#customizing-appearance).
57
+
58
+ ## Usage
59
+
60
+ ### Global Registration
61
+
62
+ ```js
63
+ import { createApp } from 'vue';
64
+ import Loop8Select from '@loop8/vue-select';
65
+ import App from './App.vue';
66
+
67
+ const app = createApp(App);
68
+ app.use(Loop8Select);
69
+ app.mount('#app');
70
+ ```
71
+
72
+ ### Local Registration
73
+
74
+ ```vue
75
+ <template>
76
+ <div>
77
+ <Loop8Select
78
+ v-model="selected"
79
+ :options="options"
80
+ :multiple="false"
81
+ name="my-select"
82
+ placeholder="Select an option"
83
+ />
84
+ </div>
85
+ </template>
86
+
87
+ <script>
88
+ import { ref } from 'vue';
89
+ import { Loop8Select } from '@loop8/vue-select';
90
+
91
+ export default {
92
+ components: {
93
+ Loop8Select
94
+ },
95
+ setup() {
96
+ const selected = ref(null);
97
+ const options = ref([
98
+ { value: 1, text: 'Option 1' },
99
+ { value: 2, text: 'Option 2' },
100
+ { value: 3, text: 'Option 3' }
101
+ ]);
102
+
103
+ return {
104
+ selected,
105
+ options
106
+ };
107
+ }
108
+ };
109
+ </script>
110
+ ```
111
+
112
+ ### With AJAX Data Loading
113
+
114
+ ```vue
115
+ <template>
116
+ <Loop8Select
117
+ v-model="selected"
118
+ :options="[]"
119
+ :ajax="ajaxConfig"
120
+ valueKey="id"
121
+ labelKey="name"
122
+ name="ajax-select"
123
+ placeholder="Search..."
124
+ />
125
+ </template>
126
+
127
+ <script>
128
+ import { ref } from 'vue';
129
+ import { Loop8Select, Loop8SelectAjaxConfig } from '@loop8/vue-select';
130
+
131
+ export default {
132
+ components: { Loop8Select },
133
+ setup() {
134
+ const selected = ref(null);
135
+
136
+ const ajaxConfig = {
137
+ url: 'https://api.example.com/search',
138
+ method: 'GET',
139
+ minimumInputLength: 2,
140
+ processResults: (data) => {
141
+ return {
142
+ results: data.items,
143
+ more: false
144
+ };
145
+ }
146
+ };
147
+
148
+ return {
149
+ selected,
150
+ ajaxConfig
151
+ };
152
+ }
153
+ };
154
+ </script>
155
+ ```
156
+
157
+ ### With Infinite Scrolling Pagination
158
+
159
+ ```vue
160
+ <template>
161
+ <Loop8Select
162
+ v-model="selected"
163
+ :options="[]"
164
+ :ajax="paginationConfig"
165
+ valueKey="id"
166
+ labelKey="name"
167
+ name="paginated-select"
168
+ placeholder="Search with infinite scrolling..."
169
+ />
170
+ </template>
171
+
172
+ <script>
173
+ import { ref } from 'vue';
174
+ import { Loop8Select } from '@loop8/vue-select';
175
+
176
+ export default {
177
+ components: { Loop8Select },
178
+ setup() {
179
+ const selected = ref(null);
180
+
181
+ const paginationConfig = {
182
+ url: 'https://api.example.com/search',
183
+ pagination: true,
184
+ limit: 20,
185
+ processResults: (data) => {
186
+ return {
187
+ results: data.items,
188
+ more: data.has_more // true if there are more results
189
+ };
190
+ }
191
+ };
192
+
193
+ return { selected, paginationConfig };
194
+ }
195
+ };
196
+ </script>
197
+ ```
198
+
199
+ ### With Custom Templates
200
+
201
+ ```vue
202
+ <template>
203
+ <Loop8Select v-model="selectedCountry" :options="countries" valueKey="code" labelKey="name">
204
+ <!-- Custom option template -->
205
+ <template #option="{ option, selected, highlighted }">
206
+ <div class="country-option" :class="{ selected, highlighted }">
207
+ <span class="flag">{{ option.flag }}</span>
208
+ <span class="name">{{ option.name }}</span>
209
+ <span class="region">{{ option.region }}</span>
210
+ </div>
211
+ </template>
212
+
213
+ <!-- Custom selected option template -->
214
+ <template #selected-option="{ option }">
215
+ <div class="selected-country">
216
+ <span class="flag">{{ option.flag }}</span>
217
+ <span class="name">{{ option.name }}</span>
218
+ </div>
219
+ </template>
220
+ </Loop8Select>
221
+ </template>
222
+
223
+ <script>
224
+ import { ref } from 'vue';
225
+ import { Loop8Select } from '@loop8/vue-select';
226
+
227
+ export default {
228
+ components: { Loop8Select },
229
+ setup() {
230
+ const selectedCountry = ref(null);
231
+ const countries = ref([
232
+ { code: 'FI', name: 'Finland', flag: '🇫🇮', region: 'Europe' },
233
+ { code: 'US', name: 'United States', flag: '🇺🇸', region: 'North America' },
234
+ { code: 'DE', name: 'Germany', flag: '🇩🇪', region: 'Europe' },
235
+ { code: 'JP', name: 'Japan', flag: '🇯🇵', region: 'Asia' }
236
+ ]);
237
+
238
+ return { selectedCountry, countries };
239
+ }
240
+ };
241
+ </script>
242
+ ```
243
+
244
+ ### With Array Values
245
+
246
+ ```vue
247
+ <template>
248
+ <Loop8Select
249
+ v-model="selected"
250
+ :options="['Option 1', 'Option 2', 'Option 3']"
251
+ name="simple-select"
252
+ />
253
+ </template>
254
+
255
+ <script>
256
+ import { ref } from 'vue';
257
+ import { Loop8Select } from '@loop8/vue-select';
258
+
259
+ export default {
260
+ components: { Loop8Select },
261
+ setup() {
262
+ const selected = ref(null);
263
+ return { selected };
264
+ }
265
+ };
266
+ </script>
267
+ ```
268
+
269
+ ### Multiple Select
270
+
271
+ ```vue
272
+ <template>
273
+ <Loop8Select
274
+ v-model="selectedItems"
275
+ :options="options"
276
+ :multiple="true"
277
+ name="multi-select"
278
+ />
279
+ </template>
280
+
281
+ <script>
282
+ import { ref } from 'vue';
283
+ import { Loop8Select } from '@loop8/vue-select';
284
+
285
+ export default {
286
+ components: { Loop8Select },
287
+ setup() {
288
+ const selectedItems = ref([]);
289
+ const options = ref([
290
+ { value: 1, text: 'Option 1' },
291
+ { value: 2, text: 'Option 2' },
292
+ { value: 3, text: 'Option 3' }
293
+ ]);
294
+
295
+ return {
296
+ selectedItems,
297
+ options
298
+ };
299
+ }
300
+ };
301
+ </script>
302
+ ```
303
+
304
+ ## Props
305
+
306
+ | Prop | Type | Default | Description |
307
+ |------|------|---------|-------------|
308
+ | modelValue | Any | null | The selected value(s), used with v-model |
309
+ | options | Array | [] | Array of options to select from (objects or primitive values) |
310
+ | placeholder | String | 'Select an option' | Placeholder text to display when no option is selected |
311
+ | multiple | Boolean | false | Allow multiple selections |
312
+ | disabled | Boolean | false | Disable the select component |
313
+ | required | Boolean | false | Mark the select as required for form validation |
314
+ | name | String | '' | Name attribute for the hidden select element (for form submission) |
315
+ | loading | Boolean | false | Show loading state |
316
+ | valueKey | String | 'value' | Key to use for option values when using object options |
317
+ | labelKey | String | 'text' | Key to use for option labels when using object options |
318
+ | ajax | Object | null | Configuration for AJAX data loading and initial value resolution |
319
+
320
+ ## Slots
321
+
322
+ | Slot | Scope | Description |
323
+ |------|-------|-------------|
324
+ | option | { option, selected, highlighted, index } | Template for rendering dropdown options |
325
+ | selected-option | { option, remove } | Template for rendering selected items |
326
+ | loading-more | none | Template for the "loading more" indicator |
327
+
328
+ ## Events
329
+
330
+ | Event | Description |
331
+ |-------|-------------|
332
+ | update:modelValue | Emitted when the selection changes, provides the selected value(s) |
333
+ | update:selectedOptions | Emitted when the selection changes, provides the full selected option object(s) including labels and other data |
334
+ | invalid-option | Emitted when an invalid option is detected. For single select, provides the invalid value. For multiple select, provides an array of invalid values. The component automatically removes invalid values from the selection. |
335
+
336
+ ### Example: Using selectedOptions
337
+
338
+ ```vue
339
+ <template>
340
+ <Loop8Select
341
+ v-model="selectedValue"
342
+ @update:selectedOptions="handleSelectedOptions"
343
+ :options="options"
344
+ />
345
+ <div v-if="selectedOption">
346
+ Selected: {{ selectedOption.text }}
347
+ </div>
348
+ </template>
349
+
350
+ <script>
351
+ import { ref } from 'vue';
352
+ import { Loop8Select } from '@loop8/vue-select';
353
+
354
+ export default {
355
+ components: { Loop8Select },
356
+ setup() {
357
+ const selectedValue = ref(null);
358
+ const selectedOption = ref(null);
359
+
360
+ const options = ref([
361
+ { value: 1, text: 'Option 1' },
362
+ { value: 2, text: 'Option 2' },
363
+ { value: 3, text: 'Option 3' }
364
+ ]);
365
+
366
+ const handleSelectedOptions = (option) => {
367
+ selectedOption.value = option;
368
+ };
369
+
370
+ return {
371
+ selectedValue,
372
+ selectedOption,
373
+ options,
374
+ handleSelectedOptions
375
+ };
376
+ }
377
+ };
378
+ </script>
379
+ ```
380
+
381
+ ## License
382
+
383
+ MIT
@@ -0,0 +1,110 @@
1
+ import type { PropType } from 'vue';
2
+ import { Loop8SelectOption, Loop8SelectAjaxConfig } from '../types';
3
+ declare const _sfc_main: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
+ modelValue: {
5
+ type: PropType<any>;
6
+ default: null;
7
+ };
8
+ options: {
9
+ type: PropType<Loop8SelectOption[]>;
10
+ default: () => never[];
11
+ };
12
+ placeholder: {
13
+ type: StringConstructor;
14
+ default: string;
15
+ };
16
+ multiple: {
17
+ type: BooleanConstructor;
18
+ default: boolean;
19
+ };
20
+ disabled: {
21
+ type: BooleanConstructor;
22
+ default: boolean;
23
+ };
24
+ required: {
25
+ type: BooleanConstructor;
26
+ default: boolean;
27
+ };
28
+ name: {
29
+ type: StringConstructor;
30
+ default: string;
31
+ };
32
+ loading: {
33
+ type: BooleanConstructor;
34
+ default: boolean;
35
+ };
36
+ valueKey: {
37
+ type: StringConstructor;
38
+ default: string;
39
+ };
40
+ labelKey: {
41
+ type: StringConstructor;
42
+ default: string;
43
+ };
44
+ ajax: {
45
+ type: PropType<Loop8SelectAjaxConfig>;
46
+ default: null;
47
+ };
48
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "invalid-option" | "update:selectedOptions")[], "update:modelValue" | "invalid-option" | "update:selectedOptions", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
49
+ modelValue: {
50
+ type: PropType<any>;
51
+ default: null;
52
+ };
53
+ options: {
54
+ type: PropType<Loop8SelectOption[]>;
55
+ default: () => never[];
56
+ };
57
+ placeholder: {
58
+ type: StringConstructor;
59
+ default: string;
60
+ };
61
+ multiple: {
62
+ type: BooleanConstructor;
63
+ default: boolean;
64
+ };
65
+ disabled: {
66
+ type: BooleanConstructor;
67
+ default: boolean;
68
+ };
69
+ required: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ name: {
74
+ type: StringConstructor;
75
+ default: string;
76
+ };
77
+ loading: {
78
+ type: BooleanConstructor;
79
+ default: boolean;
80
+ };
81
+ valueKey: {
82
+ type: StringConstructor;
83
+ default: string;
84
+ };
85
+ labelKey: {
86
+ type: StringConstructor;
87
+ default: string;
88
+ };
89
+ ajax: {
90
+ type: PropType<Loop8SelectAjaxConfig>;
91
+ default: null;
92
+ };
93
+ }>> & Readonly<{
94
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
95
+ "onInvalid-option"?: ((...args: any[]) => any) | undefined;
96
+ "onUpdate:selectedOptions"?: ((...args: any[]) => any) | undefined;
97
+ }>, {
98
+ modelValue: any;
99
+ options: Loop8SelectOption[];
100
+ placeholder: string;
101
+ multiple: boolean;
102
+ disabled: boolean;
103
+ required: boolean;
104
+ name: string;
105
+ loading: boolean;
106
+ valueKey: string;
107
+ labelKey: string;
108
+ ajax: Loop8SelectAjaxConfig;
109
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
110
+ export default _sfc_main;
@@ -0,0 +1,8 @@
1
+ import { App } from 'vue';
2
+ import Loop8Select from './components/Loop8Select.vue';
3
+ import type { Loop8SelectOption, Loop8SelectProps, Loop8SelectAjaxConfig, PaginationInfo } from './types';
4
+ export { Loop8Select, Loop8SelectOption, Loop8SelectProps, Loop8SelectAjaxConfig, PaginationInfo };
5
+ declare const _default: {
6
+ install: (app: App) => void;
7
+ };
8
+ export default _default;