sprintify-ui 0.0.107 → 0.0.109

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.
@@ -1,5 +1,6 @@
1
1
  import { PropType, ComputedRef } from 'vue';
2
2
  import { NormalizedOption, Option } from '@/types';
3
+ import { SelectConfiguration } from '@/types';
3
4
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
4
5
  modelValue: {
5
6
  default: undefined;
@@ -78,13 +79,17 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
78
79
  default(): string;
79
80
  type: StringConstructor;
80
81
  };
82
+ select: {
83
+ default: undefined;
84
+ type: PropType<SelectConfiguration | undefined>;
85
+ };
81
86
  }, {
82
87
  focus: () => void;
83
88
  blur: () => void;
84
89
  close: () => void;
85
90
  open: () => void;
86
91
  setKeywords: (input: string) => void;
87
- }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("clear" | "update:modelValue" | "close" | "scrollBottom" | "typing" | "open")[], "clear" | "update:modelValue" | "close" | "scrollBottom" | "typing" | "open", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
92
+ }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("select" | "clear" | "update:modelValue" | "close" | "scrollBottom" | "typing" | "open")[], "select" | "clear" | "update:modelValue" | "close" | "scrollBottom" | "typing" | "open", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
88
93
  modelValue: {
89
94
  default: undefined;
90
95
  type: PropType<Option | null | undefined>;
@@ -162,7 +167,12 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
162
167
  default(): string;
163
168
  type: StringConstructor;
164
169
  };
170
+ select: {
171
+ default: undefined;
172
+ type: PropType<SelectConfiguration | undefined>;
173
+ };
165
174
  }>> & {
175
+ onSelect?: ((...args: any[]) => any) | undefined;
166
176
  onScrollBottom?: ((...args: any[]) => any) | undefined;
167
177
  onClear?: ((...args: any[]) => any) | undefined;
168
178
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
@@ -173,6 +183,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
173
183
  filter: (option: NormalizedOption) => boolean;
174
184
  required: boolean;
175
185
  name: string;
186
+ select: SelectConfiguration | undefined;
176
187
  loading: boolean;
177
188
  loadingBottom: boolean;
178
189
  size: "base" | "xs" | "sm";
@@ -1,5 +1,5 @@
1
1
  import { PropType } from 'vue';
2
- import { Option } from '@/types';
2
+ import { Option, SelectConfiguration } from '@/types';
3
3
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
4
4
  modelValue: {
5
5
  default: undefined;
@@ -69,6 +69,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
69
69
  default: undefined;
70
70
  type: StringConstructor;
71
71
  };
72
+ select: {
73
+ default: undefined;
74
+ type: PropType<SelectConfiguration | undefined>;
75
+ };
72
76
  }, {
73
77
  focus: () => void | undefined;
74
78
  blur: () => void | undefined;
@@ -144,6 +148,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
144
148
  default: undefined;
145
149
  type: StringConstructor;
146
150
  };
151
+ select: {
152
+ default: undefined;
153
+ type: PropType<SelectConfiguration | undefined>;
154
+ };
147
155
  }>> & {
148
156
  onFocus?: ((...args: any[]) => any) | undefined;
149
157
  onScrollBottom?: ((...args: any[]) => any) | undefined;
@@ -153,6 +161,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
153
161
  }, {
154
162
  required: boolean;
155
163
  name: string;
164
+ select: SelectConfiguration | undefined;
156
165
  size: "base" | "xs" | "sm";
157
166
  disabled: boolean;
158
167
  placeholder: string;
@@ -1,5 +1,5 @@
1
1
  import { PropType } from 'vue';
2
- import { Option } from '@/types';
2
+ import { Option, SelectConfiguration } from '@/types';
3
3
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
4
4
  modelValue: {
5
5
  default: undefined;
@@ -73,6 +73,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
73
73
  default: undefined;
74
74
  type: StringConstructor;
75
75
  };
76
+ select: {
77
+ default: undefined;
78
+ type: PropType<SelectConfiguration | undefined>;
79
+ };
76
80
  }, {
77
81
  focus: () => void | undefined;
78
82
  blur: () => void | undefined;
@@ -152,11 +156,16 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
152
156
  default: undefined;
153
157
  type: StringConstructor;
154
158
  };
159
+ select: {
160
+ default: undefined;
161
+ type: PropType<SelectConfiguration | undefined>;
162
+ };
155
163
  }>> & {
156
164
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
157
165
  }, {
158
166
  required: boolean;
159
167
  name: string;
168
+ select: SelectConfiguration | undefined;
160
169
  size: "base" | "xs" | "sm";
161
170
  disabled: boolean;
162
171
  placeholder: string;
@@ -1,5 +1,5 @@
1
1
  import { PropType } from 'vue';
2
- import { Option } from '@/types';
2
+ import { Option, SelectConfiguration } from '@/types';
3
3
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
4
4
  modelValue: {
5
5
  type: PropType<Option | Option[] | null | undefined>;
@@ -45,6 +45,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
45
45
  default: undefined;
46
46
  type: NumberConstructor;
47
47
  };
48
+ select: {
49
+ default: undefined;
50
+ type: PropType<SelectConfiguration | undefined>;
51
+ };
48
52
  }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "update:model-value")[], "close" | "update:model-value", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
49
53
  modelValue: {
50
54
  type: PropType<Option | Option[] | null | undefined>;
@@ -90,11 +94,16 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
90
94
  default: undefined;
91
95
  type: NumberConstructor;
92
96
  };
97
+ select: {
98
+ default: undefined;
99
+ type: PropType<SelectConfiguration | undefined>;
100
+ };
93
101
  }>> & {
94
102
  onClose?: ((...args: any[]) => any) | undefined;
95
103
  "onUpdate:model-value"?: ((...args: any[]) => any) | undefined;
96
104
  }, {
97
105
  required: boolean;
106
+ select: SelectConfiguration | undefined;
98
107
  options: Option[] | undefined;
99
108
  size: "base" | "xs" | "sm";
100
109
  multiple: boolean;
@@ -163,3 +163,9 @@ export interface NotificationsConfig {
163
163
  footerLabel?: string;
164
164
  footerTo?: RouteLocationRaw;
165
165
  }
166
+ export interface SelectConfiguration {
167
+ options: Option[];
168
+ valueKey: string;
169
+ labelKey: string;
170
+ onChange: (value: OptionValue) => void;
171
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprintify-ui",
3
- "version": "0.0.107",
3
+ "version": "0.0.109",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -1,6 +1,7 @@
1
1
  import { createFieldStory, options } from '../../.storybook/utils';
2
2
  import BaseAutocomplete from './BaseAutocomplete.vue';
3
3
  import ShowValue from '@/../.storybook/components/ShowValue.vue';
4
+ import { computed } from 'vue';
4
5
 
5
6
  const sizes = ['xs', 'sm', 'base'];
6
7
 
@@ -179,6 +180,55 @@ export const SlotEmpty = (args) => {
179
180
  };
180
181
  };
181
182
 
183
+ export const WithSelect = (args) => {
184
+ return {
185
+ components: { BaseAutocomplete, ShowValue },
186
+ setup() {
187
+ const value = ref(options[0]);
188
+ const selected = ref(null);
189
+
190
+ const select = {
191
+ options: [
192
+ { label: 'All', value: 'all' },
193
+ { label: 'Jedi', value: 'jedi' },
194
+ { label: 'Sith', value: 'sith' },
195
+ ],
196
+ labelKey: 'label',
197
+ valueKey: 'value',
198
+ onChange: (option) => {
199
+ selected.value = option;
200
+ },
201
+ };
202
+
203
+ const options2 = computed(() => {
204
+ if (selected.value == 'all' || !selected.value) {
205
+ return options;
206
+ }
207
+ return options.filter((option) => option.type === selected.value);
208
+ });
209
+
210
+ return { args, value, options2, selected, select };
211
+ },
212
+ template: `
213
+ <BaseAutocomplete
214
+ v-model="value"
215
+ v-bind="args"
216
+ :options="options2"
217
+ :select="select"
218
+ >
219
+ </BaseAutocomplete>
220
+
221
+ <div class="mb-2"></div>
222
+
223
+ <p class="text-xs mb-0">Selection</p>
224
+ <ShowValue class="mt-0 mb-2" :value="selected" />
225
+
226
+ <p class="text-xs mb-0">Model Value</p>
227
+ <ShowValue class="mt-0" :value="value" />
228
+ `,
229
+ };
230
+ };
231
+
182
232
  export const Field = createFieldStory({
183
233
  component: BaseAutocomplete,
184
234
  componentName: 'BaseAutocomplete',
@@ -1,42 +1,64 @@
1
1
  <template>
2
2
  <div ref="autocomplete">
3
3
  <div class="relative z-[1]">
4
- <div class="relative">
5
- <input
6
- ref="inputElement"
7
- :value="keywords"
8
- type="text"
9
- :placeholder="
10
- placeholder ? placeholder : $t('sui.autocomplete_placeholder')
11
- "
12
- class="w-full rounded pr-9 disabled:cursor-not-allowed disabled:text-slate-300"
4
+ <div class="flex">
5
+ <select
6
+ v-if="select"
7
+ v-model="selection"
8
+ :disabled="disabled"
9
+ class="rounded-l border-r-transparent focus:z-[1] focus:border-r-blue-500 disabled:cursor-not-allowed disabled:text-slate-300 disabled:opacity-100"
13
10
  :class="[
14
11
  hasErrorInternal ? 'border-red-600' : 'border-slate-300',
15
- inputClass,
16
- !visibleFocus
17
- ? [
18
- 'focus:ring-0',
19
- hasErrorInternal
20
- ? 'focus:border-red-600'
21
- : 'focus:border-slate-300',
22
- ]
23
- : '',
12
+ inputSelectClass,
24
13
  ]"
25
- autocomplete="off"
26
- :disabled="disabled"
27
- @click="open"
28
- @input="onTextInput"
29
- @keydown="onTextKeydown"
30
- />
31
- <div
32
- class="pointer-events-none absolute top-0 left-0 flex h-full items-center justify-center"
33
- :class="[iconWrapClass]"
14
+ @change="onSelectChange"
34
15
  >
35
- <BaseIcon
36
- class="text-slate-400"
37
- :class="[iconClass]"
38
- icon="heroicons:magnifying-glass-solid"
16
+ <option
17
+ v-for="option in select.options"
18
+ :key="option[select.valueKey]"
19
+ :value="option[select.valueKey]"
20
+ >
21
+ {{ option[select.labelKey] }}
22
+ </option>
23
+ </select>
24
+ <div class="relative grow">
25
+ <input
26
+ ref="inputElement"
27
+ :value="keywords"
28
+ type="text"
29
+ :placeholder="
30
+ placeholder ? placeholder : $t('sui.autocomplete_placeholder')
31
+ "
32
+ class="relative w-full pr-9 disabled:cursor-not-allowed disabled:text-slate-300"
33
+ :class="[
34
+ select ? '-left-px rounded-r' : 'rounded',
35
+ hasErrorInternal ? 'border-red-600' : 'border-slate-300',
36
+ inputSizeClass,
37
+ !visibleFocus
38
+ ? [
39
+ 'focus:ring-0',
40
+ hasErrorInternal
41
+ ? 'focus:border-red-600'
42
+ : 'focus:border-slate-300',
43
+ ]
44
+ : '',
45
+ ]"
46
+ autocomplete="off"
47
+ :disabled="disabled"
48
+ @click="open"
49
+ @input="onTextInput"
50
+ @keydown="onTextKeydown"
39
51
  />
52
+ <div
53
+ class="pointer-events-none absolute top-0 left-0 flex h-full items-center justify-center"
54
+ :class="[iconWrapClass]"
55
+ >
56
+ <BaseIcon
57
+ class="text-slate-400"
58
+ :class="[iconClass]"
59
+ icon="heroicons:magnifying-glass-solid"
60
+ />
61
+ </div>
40
62
  </div>
41
63
  </div>
42
64
 
@@ -104,6 +126,7 @@ import { useField } from '@/composables/field';
104
126
  import { BaseIcon } from './index';
105
127
  import { useClickOutside } from '@/composables/clickOutside';
106
128
  import BaseAutocompleteDrawer from './BaseAutocompleteDrawer.vue';
129
+ import { SelectConfiguration } from '@/types';
107
130
 
108
131
  const props = defineProps({
109
132
  modelValue: {
@@ -186,6 +209,10 @@ const props = defineProps({
186
209
  },
187
210
  type: String,
188
211
  },
212
+ select: {
213
+ default: undefined,
214
+ type: Object as PropType<SelectConfiguration | undefined>,
215
+ },
189
216
  });
190
217
 
191
218
  const emit = defineEmits([
@@ -195,6 +222,7 @@ const emit = defineEmits([
195
222
  'open',
196
223
  'close',
197
224
  'scrollBottom',
225
+ 'select',
198
226
  ]);
199
227
 
200
228
  const { hasErrorInternal, emitUpdate } = useField({
@@ -388,6 +416,33 @@ function blur() {
388
416
  inputElement.value?.blur();
389
417
  }
390
418
 
419
+ function highlight() {
420
+ inputElement.value?.select();
421
+ }
422
+
423
+ const selection = ref(null) as Ref<string | null>;
424
+
425
+ watch(
426
+ () => props.select,
427
+ (select) => {
428
+ if (select && select.options.length > 0) {
429
+ selection.value = select.options[0][select.valueKey];
430
+ }
431
+ },
432
+ { immediate: true }
433
+ );
434
+
435
+ function onSelectChange(event: Event) {
436
+ focus();
437
+ open();
438
+ highlight();
439
+ const value = get(event, 'target.value', null);
440
+ if (props.select && props.select.onChange) {
441
+ props.select.onChange(value);
442
+ }
443
+ emit('select', value);
444
+ }
445
+
391
446
  const slotProps = {
392
447
  focus,
393
448
  blur,
@@ -398,7 +453,7 @@ const slotProps = {
398
453
 
399
454
  // Element Classes
400
455
 
401
- const inputClass = computed(() => {
456
+ const inputSizeClass = computed(() => {
402
457
  if (props.size == 'xs') {
403
458
  return 'xs:text-xs xs:pl-7 text-base pl-9';
404
459
  }
@@ -408,6 +463,16 @@ const inputClass = computed(() => {
408
463
  return 'text-base pl-9';
409
464
  });
410
465
 
466
+ const inputSelectClass = computed(() => {
467
+ if (props.size == 'xs') {
468
+ return 'xs:text-xs text-base';
469
+ }
470
+ if (props.size == 'sm') {
471
+ return 'xs:text-sm text-base';
472
+ }
473
+ return 'text-base';
474
+ });
475
+
411
476
  const iconClass = computed(() => {
412
477
  if (props.size == 'xs') {
413
478
  return 'xs:h-4 xs:w-4 h-5 w-5';
@@ -164,6 +164,59 @@ export const SlotEmpty = (args) => {
164
164
  };
165
165
  };
166
166
 
167
+ export const WithSelect = (args) => {
168
+ return {
169
+ components: { BaseAutocompleteFetch, ShowValue },
170
+ setup() {
171
+ const value = ref(options[0]);
172
+ const selected = ref(null);
173
+
174
+ const select = {
175
+ options: [
176
+ { label: 'All', value: 'all' },
177
+ { label: 'Video', value: 'video' },
178
+ { label: 'Article', value: 'article' },
179
+ ],
180
+ labelKey: 'label',
181
+ valueKey: 'value',
182
+ onChange: (option) => {
183
+ selected.value = option;
184
+ },
185
+ };
186
+
187
+ const url = computed(() => {
188
+ if (selected.value == 'all' || !selected.value) {
189
+ return 'https://effettandem.com/api/content/articles';
190
+ }
191
+ return (
192
+ 'https://effettandem.com/api/content/articles' +
193
+ '?type=' +
194
+ selected.value
195
+ );
196
+ });
197
+
198
+ return { args, value, url, selected, select };
199
+ },
200
+ template: `
201
+ <BaseAutocompleteFetch
202
+ v-model="value"
203
+ v-bind="args"
204
+ :url="url"
205
+ :select="select"
206
+ >
207
+ </BaseAutocompleteFetch>
208
+
209
+ <div class="mb-2"></div>
210
+
211
+ <p class="text-xs mb-0">Selection</p>
212
+ <ShowValue class="mt-0 mb-2" :value="selected" />
213
+
214
+ <p class="text-xs mb-0">Model Value</p>
215
+ <ShowValue class="mt-0" :value="value" />
216
+ `,
217
+ };
218
+ };
219
+
167
220
  export const Field = createFieldStory({
168
221
  component: BaseAutocompleteFetch,
169
222
  componentName: 'BaseAutocompleteFetch',
@@ -19,6 +19,7 @@
19
19
  :visible-focus="visibleFocus"
20
20
  :show-empty-option="showEmptyOption"
21
21
  :empty-option-label="emptyOptionLabel"
22
+ :select="select"
22
23
  :filter="filterOptions"
23
24
  @clear="onClear"
24
25
  @open="onOpen"
@@ -51,7 +52,7 @@
51
52
  import { config } from '@/index';
52
53
  import { debounce, throttle } from 'lodash';
53
54
  import { PropType, Ref } from 'vue';
54
- import { Option } from '@/types';
55
+ import { Option, SelectConfiguration } from '@/types';
55
56
  import BaseAutocomplete from './BaseAutocomplete.vue';
56
57
 
57
58
  /**
@@ -132,6 +133,10 @@ const props = defineProps({
132
133
  default: undefined,
133
134
  type: String,
134
135
  },
136
+ select: {
137
+ default: undefined,
138
+ type: Object as PropType<SelectConfiguration | undefined>,
139
+ },
135
140
  });
136
141
 
137
142
  const emit = defineEmits([
@@ -187,6 +192,15 @@ const scrollBottom = throttle(() => {
187
192
  }
188
193
  }, 500);
189
194
 
195
+ watch(
196
+ () => props.url,
197
+ () => {
198
+ page.value = 1;
199
+ reachedEnd.value = false;
200
+ search();
201
+ }
202
+ );
203
+
190
204
  function search() {
191
205
  if (fetching.value) {
192
206
  return;
@@ -163,6 +163,59 @@ export const SlotEmpty = (args) => {
163
163
  };
164
164
  };
165
165
 
166
+ export const WithSelect = (args) => {
167
+ return {
168
+ components: { BaseBelongsTo, ShowValue },
169
+ setup() {
170
+ const value = ref(options[0]);
171
+ const selected = ref(null);
172
+
173
+ const select = {
174
+ options: [
175
+ { label: 'All', value: 'all' },
176
+ { label: 'Video', value: 'video' },
177
+ { label: 'Article', value: 'article' },
178
+ ],
179
+ labelKey: 'label',
180
+ valueKey: 'value',
181
+ onChange: (option) => {
182
+ selected.value = option;
183
+ },
184
+ };
185
+
186
+ const url = computed(() => {
187
+ if (selected.value == 'all' || !selected.value) {
188
+ return 'https://effettandem.com/api/content/articles';
189
+ }
190
+ return (
191
+ 'https://effettandem.com/api/content/articles' +
192
+ '?type=' +
193
+ selected.value
194
+ );
195
+ });
196
+
197
+ return { args, value, url, selected, select };
198
+ },
199
+ template: `
200
+ <BaseBelongsTo
201
+ v-model="value"
202
+ v-bind="args"
203
+ :url="url"
204
+ :select="select"
205
+ >
206
+ </BaseBelongsTo>
207
+
208
+ <div class="mb-2"></div>
209
+
210
+ <p class="text-xs mb-0">Selection</p>
211
+ <ShowValue class="mt-0 mb-2" :value="selected" />
212
+
213
+ <p class="text-xs mb-0">Model Value</p>
214
+ <ShowValue class="mt-0" :value="value" />
215
+ `,
216
+ };
217
+ };
218
+
166
219
  export const Field = createFieldStory({
167
220
  component: BaseBelongsTo,
168
221
  componentName: 'BaseBelongsTo',
@@ -17,6 +17,7 @@
17
17
  :show-empty-option="showEmptyOption"
18
18
  :empty-option-label="emptyOptionLabel"
19
19
  :visible-focus="visibleFocus"
20
+ :select="select"
20
21
  @update:model-value="onUpdate"
21
22
  >
22
23
  <template #option="optionProps">
@@ -36,7 +37,7 @@ import { PropType, Ref } from 'vue';
36
37
  import { AxiosResponse } from 'axios';
37
38
  import { config } from '@/index';
38
39
  import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
39
- import { Option } from '@/types';
40
+ import { Option, SelectConfiguration } from '@/types';
40
41
 
41
42
  const props = defineProps({
42
43
  modelValue: {
@@ -113,6 +114,10 @@ const props = defineProps({
113
114
  default: undefined,
114
115
  type: String,
115
116
  },
117
+ select: {
118
+ default: undefined,
119
+ type: Object as PropType<SelectConfiguration | undefined>,
120
+ },
116
121
  });
117
122
 
118
123
  const http = config.http;
@@ -9,7 +9,7 @@ const items = [];
9
9
 
10
10
  for (let i = 0; i < 100; i++) {
11
11
  items.push({
12
- label: `Item ${i + 1}`,
12
+ label: `Item number #${i + 1}`,
13
13
  });
14
14
  }
15
15