sprintify-ui 0.2.14 → 0.2.15

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.
@@ -16,7 +16,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
16
16
  type: import("vue").PropType<number>;
17
17
  default: number;
18
18
  };
19
- }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "item:click"[], "item:click", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
19
+ }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("item:click" | "row:click")[], "item:click" | "row:click", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
20
20
  maxHeight: {
21
21
  type: import("vue").PropType<number>;
22
22
  default: undefined;
@@ -35,6 +35,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
35
35
  };
36
36
  }>> & {
37
37
  "onItem:click"?: ((...args: any[]) => any) | undefined;
38
+ "onRow:click"?: ((...args: any[]) => any) | undefined;
38
39
  }, {
39
40
  maxHeight: number;
40
41
  rowHeight: number;
@@ -0,0 +1,33 @@
1
+ import { PropType } from 'vue';
2
+ declare const _default: import("vue").DefineComponent<{
3
+ modelValue: {
4
+ required: true;
5
+ type: PropType<string | number | null>;
6
+ };
7
+ numberOfCharacters: {
8
+ required: true;
9
+ type: NumberConstructor;
10
+ };
11
+ type: {
12
+ default: string;
13
+ type: PropType<"numeric" | "alphanumeric">;
14
+ };
15
+ }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "update:modelValue"[], "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
16
+ modelValue: {
17
+ required: true;
18
+ type: PropType<string | number | null>;
19
+ };
20
+ numberOfCharacters: {
21
+ required: true;
22
+ type: NumberConstructor;
23
+ };
24
+ type: {
25
+ default: string;
26
+ type: PropType<"numeric" | "alphanumeric">;
27
+ };
28
+ }>> & {
29
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
30
+ }, {
31
+ type: "numeric" | "alphanumeric";
32
+ }, {}>;
33
+ export default _default;
@@ -88,8 +88,9 @@ import BaseTextarea from './BaseTextarea.vue';
88
88
  import BaseTextareaAutoresize from './BaseTextareaAutoresize.vue';
89
89
  import BaseTimeline from './BaseTimeline.vue';
90
90
  import BaseTimelineItem from './BaseTimelineItem.vue';
91
+ import BaseUniqueCode from './BaseUniqueCode.vue';
91
92
  import BaseLayoutStacked from './BaseLayoutStacked.vue';
92
93
  import BaseLayoutStackedConfigurable from './BaseLayoutStackedConfigurable.vue';
93
94
  import BaseLayoutSidebar from './BaseLayoutSidebar.vue';
94
95
  import BaseLayoutSidebarConfigurable from './BaseLayoutSidebarConfigurable.vue';
95
- export { BaseActionItem, BaseAddressForm, BaseAlert, BaseApp, BaseAppDialogs, BaseAppNotifications, BaseAutocomplete, BaseAutocompleteFetch, BaseAvatar, BaseAvatarGroup, BaseBadge, BaseBelongsTo, BaseBoolean, BaseBreadcrumbs, BaseButton, BaseButtonGroup, BaseCard, BaseCardRow, BaseCharacterCounter, BaseClickOutside, BaseClipboard, BaseColor, BaseContainer, BaseCounter, BaseCropper, BaseCropperModal, BaseDataIterator, BaseDataTable, BaseDatePicker, BaseDateSelect, BaseDescriptionList, BaseDescriptionListItem, BaseDialog, BaseDisplayRelativeTime, BaseDropdown, BaseDropdownAutocomplete, BaseEmptyState, BaseField, BaseFieldI18n, BaseFilePicker, BaseFilePickerCrop, BaseFileUploader, BaseForm, BaseGantt, BaseHasMany, BaseHeader, BaseIcon, BaseIconPicker, BaseInput, BaseInputLabel, BaseInputPercent, BaseLoadingCover, BaseMediaItem, BaseMediaLibrary, BaseMediaPreview, BaseMenu, BaseMenuItem, BaseModalCenter, BaseModalSide, BaseNavbar, BaseNavbarItem, BaseNavbarItemContent, BaseNavbarSideItem, BasePagination, BasePanel, BasePassword, BaseProgressCircle, BaseRadioGroup, BaseReadMore, BaseRichText, BaseSelect, BaseShortcut, BaseSideNavigation, BaseSideNavigationItem, BaseSkeleton, BaseStatistic, BaseStepper, BaseStepperItem, BaseSwitch, BaseSystemAlert, BaseTabs, BaseTabItem, BaseTagAutocomplete, BaseTagAutocompleteFetch, BaseTable, BaseTableColumn, BaseTextarea, BaseTextareaAutoresize, BaseTimeline, BaseTimelineItem, BaseLayoutStacked, BaseLayoutStackedConfigurable, BaseLayoutSidebar, BaseLayoutSidebarConfigurable, };
96
+ export { BaseActionItem, BaseAddressForm, BaseAlert, BaseApp, BaseAppDialogs, BaseAppNotifications, BaseAutocomplete, BaseAutocompleteFetch, BaseAvatar, BaseAvatarGroup, BaseBadge, BaseBelongsTo, BaseBoolean, BaseBreadcrumbs, BaseButton, BaseButtonGroup, BaseCard, BaseCardRow, BaseCharacterCounter, BaseClickOutside, BaseClipboard, BaseColor, BaseContainer, BaseCounter, BaseCropper, BaseCropperModal, BaseDataIterator, BaseDataTable, BaseDatePicker, BaseDateSelect, BaseDescriptionList, BaseDescriptionListItem, BaseDialog, BaseDisplayRelativeTime, BaseDropdown, BaseDropdownAutocomplete, BaseEmptyState, BaseField, BaseFieldI18n, BaseFilePicker, BaseFilePickerCrop, BaseFileUploader, BaseForm, BaseGantt, BaseHasMany, BaseHeader, BaseIcon, BaseIconPicker, BaseInput, BaseInputLabel, BaseInputPercent, BaseLoadingCover, BaseMediaItem, BaseMediaLibrary, BaseMediaPreview, BaseMenu, BaseMenuItem, BaseModalCenter, BaseModalSide, BaseNavbar, BaseNavbarItem, BaseNavbarItemContent, BaseNavbarSideItem, BasePagination, BasePanel, BasePassword, BaseProgressCircle, BaseRadioGroup, BaseReadMore, BaseRichText, BaseSelect, BaseShortcut, BaseSideNavigation, BaseSideNavigationItem, BaseSkeleton, BaseStatistic, BaseStepper, BaseStepperItem, BaseSwitch, BaseSystemAlert, BaseTabs, BaseTabItem, BaseTagAutocomplete, BaseTagAutocompleteFetch, BaseTable, BaseTableColumn, BaseTextarea, BaseTextareaAutoresize, BaseTimeline, BaseTimelineItem, BaseUniqueCode, BaseLayoutStacked, BaseLayoutStackedConfigurable, BaseLayoutSidebar, BaseLayoutSidebarConfigurable, };
@@ -18,6 +18,7 @@ declare const messages: {
18
18
  and: string;
19
19
  apply: string;
20
20
  apply_filters: string;
21
+ authentication_code: string;
21
22
  autocomplete_placeholder: string;
22
23
  cancel: string;
23
24
  city: string;
@@ -105,6 +106,7 @@ declare const messages: {
105
106
  and: string;
106
107
  apply: string;
107
108
  apply_filters: string;
109
+ authentication_code: string;
108
110
  autocomplete_placeholder: string;
109
111
  cancel: string;
110
112
  city: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprintify-ui",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -59,11 +59,15 @@ const Template = (args) => ({
59
59
  alert(`Item "${item.name}" clicked`);
60
60
  }
61
61
 
62
- return { args, onItemClick };
62
+ function onRowClick(item) {
63
+ alert(`Row "${item.name}" clicked`);
64
+ }
65
+
66
+ return { args, onItemClick, onRowClick };
63
67
  },
64
68
  template: `
65
69
  <BaseCard clipped>
66
- <BaseGantt v-bind="args" @item:click="onItemClick">
70
+ <BaseGantt v-bind="args" @item:click="onItemClick" @row:click="onRowClick">
67
71
  </BaseGantt>
68
72
  </BaseCard>
69
73
  `,
@@ -34,6 +34,7 @@
34
34
  :style="{
35
35
  height: `${props.rowHeight}px`,
36
36
  }"
37
+ @click="$emit('row:click', row)"
37
38
  >
38
39
  <slot
39
40
  name="sidebarItem"
@@ -250,6 +251,7 @@ const props = withDefaults(defineProps<{
250
251
 
251
252
  defineEmits([
252
253
  'item:click',
254
+ 'row:click',
253
255
  ]);
254
256
 
255
257
  // Config
@@ -0,0 +1,36 @@
1
+ import BaseUniqueCode from './BaseUniqueCode.vue';
2
+ import ShowValue from '@/../.storybook/components/ShowValue.vue';
3
+
4
+ export default {
5
+ title: 'Components/BaseUniqueCode',
6
+ component: BaseUniqueCode,
7
+ argTypes: {
8
+ type: {
9
+ control: { type: 'select' },
10
+ options: ['numeric', 'alphanumeric'],
11
+ },
12
+ },
13
+ };
14
+
15
+ const Template = (args) => ({
16
+ components: { BaseUniqueCode, ShowValue },
17
+ setup() {
18
+ const value = ref('');
19
+ return { args, value };
20
+ },
21
+ template: `
22
+ <BaseUniqueCode v-model="value" v-bind="args" class="w-full"></BaseUniqueCode>
23
+ <ShowValue :value="value" />
24
+ `,
25
+ });
26
+
27
+ export const Numeric = Template.bind({});
28
+ Numeric.args = {
29
+ numberOfCharacters: 4,
30
+ };
31
+
32
+ export const Alphanumeric = Template.bind({});
33
+ Alphanumeric.args = {
34
+ numberOfCharacters: 4,
35
+ type: 'text'
36
+ };
@@ -0,0 +1,209 @@
1
+ <template>
2
+ <div class="unique-code">
3
+ <input
4
+ v-for="index in props.numberOfCharacters "
5
+ :key="index"
6
+ ref="codeInputs"
7
+ class="border-t-0 border-x-0 border-b-2 border-gray-300 w-[70px] h-[90px]
8
+ text-4xl font-normal text-gray-700 text-center p-0 m-0 mx-2 outline-none
9
+ duration-200 focus:outline-none focus:shadow-none focus:border-b-primary-500 focus:ring-0"
10
+
11
+ type="text"
12
+ maxlength="1"
13
+ :pattern="pattern"
14
+ :value="uniqueCode[index] || ''"
15
+ @input="handleCodeInput(index, $event)"
16
+ @paste="handleCodePaste(index, $event)"
17
+ @keydown="handleCodeKeyDown(index, $event)"
18
+ >
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { ref, onMounted, nextTick, PropType } from 'vue';
24
+
25
+ const props = defineProps({
26
+ modelValue: {
27
+ required: true,
28
+ type: [String, Number, null] as PropType<string | number | null>,
29
+ },
30
+ numberOfCharacters: {
31
+ required: true,
32
+ type: Number,
33
+ },
34
+ type: {
35
+ default: "numeric",
36
+ type: String as PropType<'numeric' | 'alphanumeric'>,
37
+ }
38
+ });
39
+
40
+ const emit = defineEmits(['update:modelValue']);
41
+
42
+ const pattern = computed(() => {
43
+ if (props.type === 'alphanumeric') {
44
+ return "[A-Za-z0-9]+";
45
+ }
46
+
47
+ return "[0-9]*";
48
+ })
49
+
50
+ const form = reactive({
51
+ code: '',
52
+ });
53
+
54
+ const codeInputs = ref<(HTMLInputElement | null)[]>([]);
55
+ const uniqueCode = ref<string[]>(Array(props.numberOfCharacters).fill(''));
56
+ const prvIndex = ref(0);
57
+
58
+ watch(
59
+ () => form.code,
60
+ () => {
61
+ emit('update:modelValue', form.code);
62
+ },
63
+ { immediate: true }
64
+ );
65
+
66
+ // Max length check for each input
67
+ const maxLengthCheck = (input: HTMLInputElement) => {
68
+ if (input.value.length > input.maxLength) {
69
+ input.value = input.value.slice(0, input.maxLength);
70
+ }
71
+ };
72
+
73
+ // Handle code input
74
+ const handleCodeInput = (index: number, event: Event) => {
75
+ const input = event.target as HTMLInputElement;
76
+ maxLengthCheck(input);
77
+
78
+ const nextIndex = index < props.numberOfCharacters ? index + 1 : index;
79
+
80
+ if (index >= 0 && index <= props.numberOfCharacters) {
81
+ if (props.type === 'numeric') {
82
+ const inputValue = parseInt(input.value);
83
+ if (isNaN(inputValue) || inputValue < 0 || inputValue > 9) {
84
+ input.value = '';
85
+ uniqueCode.value[index] = '';
86
+
87
+ return;
88
+ }
89
+ }
90
+
91
+ if (input.value !== '') {
92
+ uniqueCode.value[index] = input.value;
93
+ codeInputs.value[nextIndex - 1]?.focus();
94
+ }
95
+ console.log('ccc');
96
+
97
+ form.code += input.value;
98
+ uniqueCode.value[index] = input.value;
99
+ if (form.code.length > props.numberOfCharacters) {
100
+ form.code = form.code.slice(0, props.numberOfCharacters);
101
+ }
102
+ }
103
+ };
104
+
105
+ // Handle code keydown events
106
+ function handleCodeKeyDown(index: number, event: KeyboardEvent) {
107
+ const input = event.target as HTMLInputElement;
108
+
109
+ if (index === 0 && event.key === 'Backspace') {
110
+ return;
111
+ }
112
+
113
+ if (index === props.numberOfCharacters + 1) {
114
+ return;
115
+ }
116
+
117
+ prvIndex.value = index - 1;
118
+
119
+ if (event.key === 'Backspace') {
120
+ if (index > 0 && index <= props.numberOfCharacters) {
121
+
122
+ setTimeout(() => {
123
+ codeInputs.value[prvIndex.value - 1]?.focus();
124
+ }, 10);
125
+
126
+ input.value = ''
127
+ form.code = form.code.slice(0, prvIndex.value);
128
+ }
129
+ }
130
+
131
+ if (event.key === 'ArrowRight') {
132
+ codeInputs.value[index]?.focus();
133
+ }
134
+
135
+ if (event.key === 'ArrowLeft') {
136
+ codeInputs.value[prvIndex.value - 1]?.focus();
137
+ }
138
+ }
139
+
140
+ // Handle code paste
141
+ const handleCodePaste = (index: number, event: ClipboardEvent) => {
142
+ const pastedData = event.clipboardData?.getData('text/plain') || '';
143
+
144
+ let data = [] as string[];
145
+
146
+ if (props.type === 'alphanumeric') {
147
+ data = pastedData.split('').filter((char) => /^[A-Za-z0-9]+$/.test(char));
148
+ } else {
149
+ data = pastedData.split('').filter((char) => !isNaN(Number(char)));
150
+ }
151
+
152
+ // Reset code
153
+ form.code = '';
154
+
155
+ for (let i = 0; i < data.length && i < props.numberOfCharacters; i++) {
156
+ uniqueCode.value[index + i] = data[i];
157
+ form.code += data[i];
158
+ }
159
+
160
+ // Focus the next input after paste
161
+ codeInputs.value[index + data.length]?.focus();
162
+
163
+ event.preventDefault();
164
+ };
165
+
166
+ // Focus the first input on component mount
167
+ onMounted(async () => {
168
+ await nextTick();
169
+ codeInputs.value = Array.from(
170
+ { length: props.numberOfCharacters },
171
+ (_, index) => codeInputs.value[index]
172
+ );
173
+ const firstInput = codeInputs.value[0];
174
+ if (firstInput !== null) {
175
+ firstInput.focus();
176
+ }
177
+ });
178
+
179
+ </script>
180
+
181
+ <style scoped>
182
+ /* .unique-code input {
183
+ appearance: none;
184
+ -moz-appearance: textfield;
185
+ -webkit-appearance: textfield;
186
+ border: none;
187
+ border-bottom: 2px solid #e2e8f0;
188
+ width: 70px;
189
+ height: 90px;
190
+ font-size: 4rem;
191
+ font-weight: normal;
192
+ color: #484747;
193
+ text-align: center;
194
+ padding: 0;
195
+ margin: 0 .5rem;
196
+ outline: none;
197
+ transition: border-color 0.2s;
198
+ }
199
+
200
+ .unique-code input:focus {
201
+ box-shadow: none;
202
+ border-bottom-color: #667eea;
203
+ }
204
+ .unique-code input::-webkit-inner-spin-button,
205
+ .unique-code input::-webkit-outer-spin-button {
206
+ -webkit-appearance: none;
207
+ margin: 0;
208
+ } */
209
+ </style>
@@ -88,6 +88,7 @@ import BaseTextarea from './BaseTextarea.vue';
88
88
  import BaseTextareaAutoresize from './BaseTextareaAutoresize.vue';
89
89
  import BaseTimeline from './BaseTimeline.vue';
90
90
  import BaseTimelineItem from './BaseTimelineItem.vue';
91
+ import BaseUniqueCode from './BaseUniqueCode.vue';
91
92
 
92
93
  import BaseLayoutStacked from './BaseLayoutStacked.vue';
93
94
  import BaseLayoutStackedConfigurable from './BaseLayoutStackedConfigurable.vue';
@@ -185,6 +186,7 @@ export {
185
186
  BaseTextareaAutoresize,
186
187
  BaseTimeline,
187
188
  BaseTimelineItem,
189
+ BaseUniqueCode,
188
190
  BaseLayoutStacked,
189
191
  BaseLayoutStackedConfigurable,
190
192
  BaseLayoutSidebar,
package/src/lang/en.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "and": "and",
11
11
  "apply": "Apply",
12
12
  "apply_filters": "Apply filters",
13
+ "authentication_code": "Authentication code",
13
14
  "autocomplete_placeholder": "Type to start your search",
14
15
  "cancel": "Cancel",
15
16
  "city": "City",
@@ -84,4 +85,4 @@
84
85
  "you_can_upload_up_to_n_files": "You can upload one file at most|You can upload up to {count} files",
85
86
  "you_cannot_select_more_than_x_items": "You can't select more than one item|You can't select more than {count} items"
86
87
  }
87
- }
88
+ }
package/src/lang/fr.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "and": "et",
11
11
  "apply": "Appliquer",
12
12
  "apply_filters": "Appliquer les filtres",
13
+ "authentication_code": "Code d'authentification",
13
14
  "autocomplete_placeholder": "Taper pour lancer votre recherche",
14
15
  "cancel": "Annuler",
15
16
  "city": "Ville",
@@ -84,4 +85,4 @@
84
85
  "you_can_upload_up_to_n_files": "Vous pouvez télécharger un fichier au maximum|Vous pouvez télécharger jusqu'à {count} fichiers",
85
86
  "you_cannot_select_more_than_x_items": "Vous ne pouvez pas sélectionner plus de un élément|Vous ne pouvez pas sélectionner plus de {count} éléments"
86
87
  }
87
- }
88
+ }