Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7fbf9e1

Browse filesBrowse files
committed
update InputField
1 parent a90f1a9 commit 7fbf9e1
Copy full SHA for 7fbf9e1

File tree

Expand file treeCollapse file tree

4 files changed

+459
-458
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+459
-458
lines changed

‎.gitignore

Copy file name to clipboardExpand all lines: .gitignore
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ deprecated
1616
# Editor directories and files
1717
.idea
1818
.vscode
19+
.fleet
1920
*.suo
2021
*.ntvs*
2122
*.njsproj

‎src/fields/InputField.vue

Copy file name to clipboardExpand all lines: src/fields/InputField.vue
+127-145Lines changed: 127 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,106 @@
1+
<script lang="ts" setup>
2+
import { Icon } from '@/common'
3+
4+
import { BN } from '@/utils/math.util'
5+
import { computed, getCurrentInstance, ref, useAttrs, useSlots } from 'vue'
6+
7+
type INPUT_TYPES = 'text' | 'number' | 'password'
8+
9+
const props = withDefaults(
10+
defineProps<{
11+
modelValue: string | number
12+
label?: string
13+
placeholder?: string
14+
type?: INPUT_TYPES
15+
errorMessage?: string
16+
}>(),
17+
{
18+
type: 'text',
19+
label: '',
20+
placeholder: ' ',
21+
errorMessage: '',
22+
},
23+
)
24+
25+
const emit = defineEmits<{
26+
(e: 'update:modelValue', value: number | string): void
27+
}>()
28+
29+
const attrs = useAttrs()
30+
31+
const slots = useSlots()
32+
33+
const uid = getCurrentInstance()?.uid
34+
35+
const isPasswordShown = ref(false)
36+
37+
const isNumberType = computed(() => props.type === 'number')
38+
const isPasswordType = computed(() => props.type === 'password')
39+
40+
const min = computed((): string => (attrs?.min as string) || '')
41+
const max = computed((): string => (attrs?.max as string) || '')
42+
43+
const isDisabled = computed(() =>
44+
['', 'disabled', true].includes(attrs.disabled as string | boolean),
45+
)
46+
47+
const isReadonly = computed(() =>
48+
['', 'readonly', true].includes(attrs.readonly as string | boolean),
49+
)
50+
51+
const listeners = computed(() => ({
52+
input: (event: Event) => {
53+
const eventTarget = event.target as HTMLInputElement
54+
if (isNumberType.value) {
55+
eventTarget.value = normalizeRange(eventTarget.value)
56+
}
57+
if (props.modelValue === eventTarget.value) return
58+
59+
emit('update:modelValue', eventTarget.value)
60+
},
61+
}))
62+
63+
const inputClasses = computed(() =>
64+
[
65+
...(slots.nodeLeft ? ['input-field--node-left'] : []),
66+
...(slots.nodeRight || isPasswordType.value
67+
? ['input-field--node-right']
68+
: []),
69+
...(isDisabled.value ? ['input-field--disabled'] : []),
70+
...(isReadonly.value ? ['input-field--readonly'] : []),
71+
...(props.errorMessage ? ['input-field--error'] : []),
72+
].join(' '),
73+
)
74+
75+
const normalizeRange = (value: string | number): string => {
76+
let result = value
77+
78+
if (min.value && new BN(value).compare(min.value) < 0) {
79+
result = min.value
80+
} else if (max.value && new BN(value).compare(max.value) > 0) {
81+
result = max.value
82+
}
83+
84+
return result as string
85+
}
86+
87+
const setHeightCSSVar = (element: HTMLElement) => {
88+
element.style.setProperty(
89+
'--field-error-msg-height',
90+
`${element.scrollHeight}px`,
91+
)
92+
}
93+
</script>
94+
195
<template>
296
<div class="input-field" :class="inputClasses">
397
<label v-if="label" :for="`input-field--${uid}`" class="input-field__label">
498
{{ label }}
599
</label>
6100
<div class="input-field__input-wrp">
101+
<div v-if="$slots.nodeLeft" class="input-field__node-left-wrp">
102+
<slot name="nodeLeft" />
103+
</div>
7104
<input
8105
class="input-field__input"
9106
:id="`input-field--${uid}`"
@@ -17,18 +114,21 @@
17114
:max="max"
18115
:disabled="isDisabled || isReadonly"
19116
/>
20-
<div v-if="isPasswordType || iconName" class="input-field__icon-wrp">
117+
<div
118+
v-if="$slots.nodeRight || isPasswordType"
119+
class="input-field__node-right-wrp"
120+
>
21121
<button
22-
type="button"
23122
v-if="isPasswordType"
123+
type="button"
24124
@click="isPasswordShown = !isPasswordShown"
25125
>
26126
<icon
27-
class="input-field__icon"
127+
class="input-field__password-icon"
28128
:name="isPasswordShown ? $icons.eye : $icons.eyeOff"
29129
/>
30130
</button>
31-
<icon v-else class="input-field__icon" :name="iconName" />
131+
<slot v-else name="nodeRight" />
32132
</div>
33133
</div>
34134
<transition
@@ -43,129 +143,6 @@
43143
</div>
44144
</template>
45145

46-
<script lang="ts">
47-
import { Icon } from '@/common'
48-
49-
import { BN } from '@/utils/math.util'
50-
import {
51-
computed,
52-
defineComponent,
53-
getCurrentInstance,
54-
PropType,
55-
ref,
56-
} from 'vue'
57-
import { ICON_NAMES } from '@/enums'
58-
59-
enum INPUT_TYPES {
60-
text = 'text',
61-
password = 'password',
62-
number = 'number',
63-
}
64-
65-
enum EVENTS {
66-
updateModelValue = 'update:model-value',
67-
}
68-
69-
enum SCHEMES {
70-
iconLeft = 'icon-left',
71-
}
72-
73-
export default defineComponent({
74-
name: 'input-field',
75-
components: { Icon },
76-
props: {
77-
modelValue: { type: [String, Number], default: '' },
78-
label: { type: String, default: '' },
79-
placeholder: { type: String, default: ' ' },
80-
type: {
81-
type: String as PropType<INPUT_TYPES>,
82-
default: INPUT_TYPES.text,
83-
},
84-
schemes: { type: String as PropType<SCHEMES>, default: '' },
85-
errorMessage: { type: String, default: '' },
86-
iconName: { type: String as PropType<ICON_NAMES>, default: '' },
87-
},
88-
emits: Object.values(EVENTS),
89-
setup(props, { emit, attrs }) {
90-
const uid = getCurrentInstance()?.uid
91-
const isPasswordShown = ref(false)
92-
93-
const isNumberType = computed(() => props.type === INPUT_TYPES.number)
94-
const isPasswordType = computed(() => props.type === INPUT_TYPES.password)
95-
96-
const min = computed((): string => (attrs?.min as string) || '')
97-
const max = computed((): string => (attrs?.max as string) || '')
98-
99-
const isDisabled = computed(() =>
100-
['', 'disabled', true].includes(attrs.disabled as string | boolean),
101-
)
102-
103-
const isReadonly = computed(() =>
104-
['', 'readonly', true].includes(attrs.readonly as string | boolean),
105-
)
106-
107-
const listeners = computed(() => ({
108-
input: (event: Event) => {
109-
const eventTarget = event.target as HTMLInputElement
110-
if (isNumberType.value) {
111-
eventTarget.value = normalizeRange(eventTarget.value)
112-
}
113-
if (props.modelValue === eventTarget.value) return
114-
115-
emit(EVENTS.updateModelValue, eventTarget.value)
116-
},
117-
}))
118-
119-
const inputClasses = computed(() => {
120-
const _schemes = props.schemes
121-
const classList = [
122-
...(_schemes ? [_schemes.split(' ')] : []),
123-
...(isDisabled.value ? ['disabled'] : []),
124-
...(isReadonly.value ? ['readonly'] : []),
125-
...(props.errorMessage ? ['error'] : []),
126-
...(props.iconName || isPasswordType ? ['iconed'] : []),
127-
]
128-
129-
return classList.map(el => `input-field--${el}`).join(' ')
130-
})
131-
132-
const normalizeRange = (value: string | number): string => {
133-
let result = value
134-
135-
if (min.value && new BN(value).compare(min.value) < 0) {
136-
result = min.value
137-
} else if (max.value && new BN(value).compare(max.value) > 0) {
138-
result = max.value
139-
}
140-
141-
return result as string
142-
}
143-
144-
const setHeightCSSVar = (element: HTMLElement) => {
145-
element.style.setProperty(
146-
'--field-error-msg-height',
147-
`${element.scrollHeight}px`,
148-
)
149-
}
150-
151-
return {
152-
uid,
153-
isPasswordShown,
154-
155-
listeners,
156-
isDisabled,
157-
isReadonly,
158-
min,
159-
max,
160-
inputClasses,
161-
isPasswordType,
162-
163-
setHeightCSSVar,
164-
}
165-
},
166-
})
167-
</script>
168-
169146
<style lang="scss" scoped>
170147
.input-field {
171148
display: flex;
@@ -246,13 +223,12 @@ export default defineComponent({
246223
border-color: var(--field-error);
247224
}
248225
249-
.input-field--iconed & {
250-
padding-right: calc(var(--field-padding-right) * 3);
226+
.input-field--node-left & {
227+
padding-left: calc(var(--field-padding-left) * 3);
251228
}
252229
253-
.input-field--icon-left & {
254-
padding-right: var(--field-padding-right);
255-
padding-left: calc(var(--field-padding-right) * 3);
230+
.input-field--node-right & {
231+
padding-right: calc(var(--field-padding-right) * 3);
256232
}
257233
258234
&:not([disabled]):focus {
@@ -266,21 +242,27 @@ export default defineComponent({
266242
}
267243
}
268244
269-
.input-field__icon-wrp {
270-
display: flex;
271-
justify-content: center;
272-
align-items: center;
245+
.input-field__node-left-wrp {
246+
overflow: hidden;
273247
position: absolute;
274248
top: 50%;
275-
right: calc(var(--field-padding-right) * 3 / 2);
276-
transform: translate(50%, -50%);
277-
278-
.input-field--icon-left & {
279-
right: 0;
280-
left: calc(var(--field-padding-right) * 3 / 2);
281-
transform: translate(-50%, -50%);
282-
width: max-content;
283-
}
249+
left: var(--field-padding-left);
250+
transform: translateY(-50%);
251+
color: inherit;
252+
max-height: 100%;
253+
}
254+
255+
.input-field__node-right-wrp {
256+
position: absolute;
257+
top: 50%;
258+
right: var(--field-padding-right);
259+
transform: translateY(-50%);
260+
color: inherit;
261+
}
262+
263+
.input-field__password-icon {
264+
max-width: toRem(24);
265+
max-height: toRem(24);
284266
}
285267
286268
.input-field__icon {

‎src/pages/UiKitPage.vue

Copy file name to clipboardExpand all lines: src/pages/UiKitPage.vue
+24-7Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,20 @@ const throwBusInfo = () => {
220220
v-model="form.inputValue"
221221
:label="'label'"
222222
:placeholder="$t('ui-kit-page.some-placeholder')"
223-
:icon-name="$icons.dotsVertical"
224-
/>
223+
>
224+
<template #nodeRight>
225+
<icon class="ui-kit-page__input-icon" :name="$icons.dotsVertical" />
226+
</template>
227+
</input-field>
225228
<input-field
226229
v-model="form.inputValue"
227-
schemes="icon-left"
228230
:label="'label'"
229231
:placeholder="$t('ui-kit-page.some-placeholder')"
230-
:icon-name="$icons.dotsVertical"
231-
/>
232+
>
233+
<template #nodeLeft>
234+
<icon class="ui-kit-page__input-icon" :name="$icons.dotsVertical" />
235+
</template>
236+
</input-field>
232237
<input-field
233238
v-model="form.inputValue"
234239
type="password"
@@ -240,7 +245,14 @@ const throwBusInfo = () => {
240245
:label="$t('ui-kit-page.some-label')"
241246
:error-message="$t('ui-kit-page.some-error-message')"
242247
:placeholder="$t('ui-kit-page.some-placeholder')"
243-
/>
248+
>
249+
<template #nodeLeft>
250+
<icon class="ui-kit-page__input-icon" :name="$icons.dotsVertical" />
251+
</template>
252+
<template #nodeRight>
253+
<icon class="ui-kit-page__input-icon" :name="$icons.dotsVertical" />
254+
</template>
255+
</input-field>
244256
<input-field
245257
v-model="form.inputValue"
246258
:label="$t('ui-kit-page.some-label')"
@@ -275,7 +287,7 @@ const throwBusInfo = () => {
275287
<template #head="{ collapse }">
276288
<app-button
277289
class="ui-kit-page__collapse-btn"
278-
schemes="flat"
290+
scheme="flat"
279291
:text="$t('ui-kit-page.collapse-btn')"
280292
@click="collapse.toggle"
281293
>
@@ -588,4 +600,9 @@ const throwBusInfo = () => {
588600
height: toRem(24);
589601
}
590602
}
603+
604+
.ui-kit-page__input-icon {
605+
max-width: toRem(24);
606+
max-height: toRem(24);
607+
}
591608
</style>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.