renusify 2.5.2 → 3.0.1
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/components/app/index.vue +74 -22
- package/components/app/toast/index.vue +76 -71
- package/components/app/toast/toast.vue +62 -44
- package/components/avatar/index.vue +207 -84
- package/components/button/buttonConfirm.vue +53 -26
- package/components/button/buttonGroup.js +0 -2
- package/components/button/buttonGroup.vue +310 -62
- package/components/button/index.vue +584 -100
- package/components/calendar/index.js +0 -2
- package/components/calendar/index.vue +326 -262
- package/components/calendar/month.vue +64 -55
- package/components/calendar/year.vue +30 -25
- package/components/card/index.vue +139 -59
- package/components/codeEditor/highlightCss.vue +38 -39
- package/components/codeEditor/highlightHtml.vue +64 -64
- package/components/codeEditor/highlightJs.vue +37 -38
- package/components/codeEditor/index.vue +129 -79
- package/components/codeEditor/run.vue +225 -39
- package/components/codeEditor/useCodeFormatter.js +150 -0
- package/components/confirm/index.vue +139 -80
- package/components/container/col.vue +5 -4
- package/components/container/divider.vue +28 -19
- package/components/container/index.vue +34 -15
- package/components/container/row.vue +26 -9
- package/components/container/spacer.vue +2 -4
- package/components/container/style.scss +3 -0
- package/components/content/index.vue +49 -32
- package/components/cropper/index.vue +401 -244
- package/components/float/index.vue +542 -415
- package/components/form/addressInput/index.vue +184 -109
- package/components/form/camInput/index.vue +370 -244
- package/components/form/checkInput/index.vue +138 -71
- package/components/form/checkboxInput/index.vue +93 -49
- package/components/form/colorInput/Alpha.vue +81 -83
- package/components/form/colorInput/Hue.vue +91 -68
- package/components/form/colorInput/Preview.vue +43 -47
- package/components/form/colorInput/Saturation.vue +101 -86
- package/components/form/colorInput/index.vue +71 -39
- package/components/form/colorInput/picker.vue +111 -106
- package/components/form/colorInput/useColor.js +153 -0
- package/components/form/dateInput/index.vue +691 -356
- package/components/form/dateInput/month.vue +63 -54
- package/components/form/dateInput/year.vue +35 -25
- package/components/form/fileInput/index.js +0 -1
- package/components/form/fileInput/index.vue +263 -106
- package/components/form/fileInput/single.vue +332 -168
- package/components/form/groupInput/index.vue +199 -101
- package/components/form/index.vue +189 -83
- package/components/form/input/index.vue +416 -377
- package/components/form/jsonInput/JsonView.vue +54 -56
- package/components/form/jsonInput/index.vue +247 -165
- package/components/form/maskInput/index.vue +252 -132
- package/components/form/numberInput/index.js +0 -1
- package/components/form/numberInput/index.vue +226 -117
- package/components/form/passwordInput/index.js +2 -1
- package/components/form/passwordInput/index.vue +269 -102
- package/components/form/radioInput/index.vue +143 -72
- package/components/form/rangeInput/index.vue +280 -167
- package/components/form/ratingInput/index.vue +57 -57
- package/components/form/selectInput/index.js +1 -3
- package/components/form/selectInput/index.vue +584 -296
- package/components/form/switchInput/index.vue +73 -59
- package/components/form/telInput/index.js +0 -1
- package/components/form/telInput/index.vue +238 -135
- package/components/form/textArea/index.vue +72 -35
- package/components/form/textEditor/index.vue +739 -0
- package/components/form/{text-editor → textEditor}/style.scss +8 -16
- package/components/form/textInput/index.vue +54 -32
- package/components/form/timeInput/index.vue +82 -55
- package/components/form/timeInput/range.vue +115 -94
- package/components/form/timeInput/timepicker.vue +382 -449
- package/components/form/uniqueInput/index.vue +105 -48
- package/components/form/unitInput/index.vue +139 -84
- package/components/formCreator/index.js +0 -1
- package/components/formCreator/index.vue +314 -148
- package/components/highlight/index.vue +41 -25
- package/components/highlight/style.scss +2 -2
- package/components/highlight/{mixin.js → useHighlight.js} +181 -160
- package/components/icon/index.vue +79 -33
- package/components/img/index.vue +250 -147
- package/components/img/preview.vue +180 -198
- package/components/img/svgImg.vue +42 -39
- package/components/index.js +5 -20
- package/components/infinite/index.js +3 -3
- package/components/infinite/index.vue +290 -66
- package/components/map/index.vue +428 -261
- package/components/map/route.vue +794 -487
- package/components/map/select.vue +118 -58
- package/components/menu/index.vue +206 -94
- package/components/meta/meta.js +26 -3
- package/components/modal/index.vue +382 -156
- package/components/notify/index.vue +204 -86
- package/components/notify/notification.vue +38 -55
- package/components/progress/circle.vue +189 -70
- package/components/progress/line.vue +266 -46
- package/components/searchBox/index.js +1 -3
- package/components/searchBox/index.vue +194 -101
- package/components/skeleton/index.vue +45 -20
- package/components/slider/index.vue +319 -156
- package/components/swiper/index.vue +237 -108
- package/components/table/crud/footer.vue +77 -53
- package/components/table/crud/header.vue +71 -72
- package/components/table/crud/index.vue +629 -399
- package/components/table/index.vue +721 -278
- package/components/timeAgo/index.vue +145 -96
- package/components/tour/index.vue +338 -235
- package/components/tree/index.vue +235 -89
- package/components/tree/tree-element.vue +106 -106
- package/directive/animate/index.js +77 -0
- package/directive/clickOutSide/index.js +98 -0
- package/directive/drag/index.js +153 -0
- package/directive/index.js +11 -13
- package/directive/intersect/index.js +263 -0
- package/directive/mask/index.js +67 -0
- package/directive/parallax/index.js +78 -0
- package/directive/ripple/index.js +14 -0
- package/directive/scroll/index.js +272 -24
- package/directive/sortable/index.js +274 -0
- package/directive/title/index.js +75 -0
- package/directive/touch/index.js +268 -0
- package/index.js +11 -19
- package/package.json +5 -2
- package/plugins/validation/Validate.js +88 -79
- package/scripts/generate-docs.mjs +226 -0
- package/scripts/menu.mjs +240 -0
- package/scripts/parser.mjs +1086 -0
- package/style/_index.scss +7 -0
- package/style/app.scss +13 -65
- package/style/colors.scss +5 -22
- package/style/functions/index.scss +8 -0
- package/style/mixins/index.scss +17 -5
- package/style/variables/base.scss +155 -178
- package/style/variables/color.scss +0 -12
- package/style/variables/utilities.scss +0 -180
- package/tools/helper.js +0 -8
- package/tools/icons.js +7 -2
- package/tools/root.js +71 -0
- package/components/app/style.scss +0 -41
- package/components/app/toast/style.scss +0 -20
- package/components/avatar/style.scss +0 -32
- package/components/bar/bottomNav.js +0 -1
- package/components/bar/bottomNav.vue +0 -28
- package/components/bar/bottomNavigationCircle.js +0 -2
- package/components/bar/bottomNavigationCircle.vue +0 -99
- package/components/bar/scss/bottomNav.scss +0 -67
- package/components/bar/scss/toolbar.scss +0 -174
- package/components/bar/toolbar/index.js +0 -8
- package/components/bar/toolbar/index.vue +0 -35
- package/components/bar/toolbar/laptop.vue +0 -33
- package/components/bar/toolbar/menuChilds.vue +0 -41
- package/components/bar/toolbar/menuLaptop.vue +0 -41
- package/components/bar/toolbar/menuMob.vue +0 -39
- package/components/bar/toolbar/mixin.js +0 -43
- package/components/bar/toolbar/mobile.vue +0 -34
- package/components/breadcrumb/bredcrumbItem.vue +0 -39
- package/components/breadcrumb/index.js +0 -3
- package/components/breadcrumb/index.vue +0 -71
- package/components/breadcrumb/style.scss +0 -51
- package/components/button/style.scss +0 -411
- package/components/card/style.scss +0 -86
- package/components/chart/chart.js +0 -1
- package/components/chart/chart.vue +0 -69
- package/components/chart/worldMap.js +0 -2
- package/components/chart/worldMap.vue +0 -1112
- package/components/chat/MessageList.vue +0 -163
- package/components/chat/chatInput.vue +0 -150
- package/components/chat/chatMsg.vue +0 -276
- package/components/chat/index.js +0 -11
- package/components/chat/index.vue +0 -113
- package/components/chip/index.js +0 -3
- package/components/chip/index.vue +0 -77
- package/components/chip/style.scss +0 -199
- package/components/codeEditor/mixin.js +0 -145
- package/components/countdown/index.js +0 -1
- package/components/countdown/index.vue +0 -105
- package/components/form/colorInput/mixin.js +0 -132
- package/components/form/fileInput/file.js +0 -148
- package/components/form/telInput/assets/flags.png +0 -0
- package/components/form/telInput/assets/flags@2x.png +0 -0
- package/components/form/text-editor/index.vue +0 -705
- package/components/icon/style.scss +0 -17
- package/components/infinite/div.js +0 -6
- package/components/infinite/div.vue +0 -193
- package/components/infinite/page.js +0 -3
- package/components/infinite/page.vue +0 -105
- package/components/list/index.js +0 -3
- package/components/list/index.vue +0 -122
- package/components/list/style.scss +0 -66
- package/components/message/index.js +0 -4
- package/components/message/index.vue +0 -40
- package/components/modal/style.scss +0 -146
- package/components/nestable/NestableItem.vue +0 -307
- package/components/nestable/editable.js +0 -44
- package/components/nestable/index.js +0 -1
- package/components/nestable/index.vue +0 -226
- package/components/nestable/methods.js +0 -416
- package/components/progress/style.scss +0 -229
- package/components/table/style.scss +0 -338
- package/components/tabs/index.js +0 -3
- package/components/tabs/index.vue +0 -151
- package/components/timeline/index.js +0 -6
- package/components/timeline/index.vue +0 -76
- package/directive/resize/index.js +0 -30
- package/directive/skeleton/index.js +0 -27
- package/directive/skeleton/style.scss +0 -37
- package/plugins/request/Request.js +0 -68
- package/style/animation.scss +0 -94
- package/style/style.scss +0 -8
- package/tools/rootable.js +0 -75
- /package/components/form/{text-editor → textEditor}/index.js +0 -0
- /package/components/form/{text-editor → textEditor}/preview.js +0 -0
- /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
|
@@ -1,130 +1,297 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<template v-if="!hideLine">
|
|
24
|
-
<div :class="{'color-success-text':hasLength,'color-error-text':!hasLength}">
|
|
2
|
+
<r-input :active="active"
|
|
3
|
+
:class="$r.prefix+'password-input'"
|
|
4
|
+
:error="!isValid"
|
|
5
|
+
:icon="show?$r.icons.eye_off:$r.icons.eye"
|
|
6
|
+
:model-value="modelValue"
|
|
7
|
+
@icon="toggleShow"
|
|
8
|
+
@click.prevent="handleClick"
|
|
9
|
+
>
|
|
10
|
+
<input ref="inputRef"
|
|
11
|
+
v-model="lazyValue"
|
|
12
|
+
:autocomplete="autocomplete"
|
|
13
|
+
:autofocus="autofocus"
|
|
14
|
+
:placeholder="placeholder"
|
|
15
|
+
:type="show?'text':'password'"
|
|
16
|
+
@focusin="active=true"
|
|
17
|
+
@focusout="active=false"
|
|
18
|
+
@input="emitValue"
|
|
19
|
+
/>
|
|
20
|
+
<template v-if="!hideRequirements" v-slot:message>
|
|
21
|
+
<r-progress-line :color="strengthColor" :model-value="passwordStrength" class="mb-2"></r-progress-line>
|
|
22
|
+
<div :class="{'color-success-text':hasLength,'color-error-text':!hasLength}" class="msg-item">
|
|
25
23
|
<r-icon v-if="hasLength" exact v-html="$r.icons.check"></r-icon>
|
|
26
24
|
<r-icon v-else v-html="$r.icons.close"></r-icon>
|
|
27
25
|
{{ $t(['min_length_password', [minLength]]) }}
|
|
28
26
|
</div>
|
|
29
|
-
<div v-if="lowerCase" :class="{'color-success-text':hasLowerCase,'color-error-text':!hasLowerCase}"
|
|
27
|
+
<div v-if="lowerCase" :class="{'color-success-text':hasLowerCase,'color-error-text':!hasLowerCase}"
|
|
28
|
+
class="msg-item">
|
|
30
29
|
<r-icon v-if="hasLowerCase" exact v-html="$r.icons.check"></r-icon>
|
|
31
30
|
<r-icon v-else v-html="$r.icons.close"></r-icon>
|
|
32
31
|
{{ $t('lower_case_password') }}
|
|
33
32
|
</div>
|
|
34
|
-
<div v-if="number" :class="{'color-success-text':hasNumber,'color-error-text':!hasNumber}">
|
|
33
|
+
<div v-if="number" :class="{'color-success-text':hasNumber,'color-error-text':!hasNumber}" class="msg-item">
|
|
35
34
|
<r-icon v-if="hasNumber" exact v-html="$r.icons.check"></r-icon>
|
|
36
35
|
<r-icon v-else v-html="$r.icons.close"></r-icon>
|
|
37
36
|
{{ $t('number_password') }}
|
|
38
37
|
</div>
|
|
39
|
-
<div v-if="upperCase" :class="{'color-success-text':hasUpperCase,'color-error-text':!hasUpperCase}"
|
|
38
|
+
<div v-if="upperCase" :class="{'color-success-text':hasUpperCase,'color-error-text':!hasUpperCase}"
|
|
39
|
+
class="msg-item">
|
|
40
40
|
<r-icon v-if="hasUpperCase" exact v-html="$r.icons.check"></r-icon>
|
|
41
41
|
<r-icon v-else v-html="$r.icons.close"></r-icon>
|
|
42
42
|
{{ $t('upper_case_password') }}
|
|
43
43
|
</div>
|
|
44
|
-
<div v-if="specialChar" :class="{'color-success-text':hasSpecialChar,'color-error-text':!hasSpecialChar}"
|
|
44
|
+
<div v-if="specialChar" :class="{'color-success-text':hasSpecialChar,'color-error-text':!hasSpecialChar}"
|
|
45
|
+
class="msg-item">
|
|
45
46
|
<r-icon v-if="hasSpecialChar" exact v-html="$r.icons.check"></r-icon>
|
|
46
47
|
<r-icon v-else v-html="$r.icons.close"></r-icon>
|
|
47
48
|
{{ $t('special_char_password') }}
|
|
48
49
|
</div>
|
|
49
50
|
</template>
|
|
50
|
-
</
|
|
51
|
+
</r-input>
|
|
51
52
|
</template>
|
|
52
|
-
<script>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
53
|
+
<script setup>
|
|
54
|
+
import {ref, computed, watch, nextTick, useAttrs} from 'vue'
|
|
55
|
+
|
|
56
|
+
const attr = useAttrs()
|
|
57
|
+
const placeholder = attr.placeholder
|
|
58
|
+
const autofocus = attr.autofocus
|
|
59
|
+
|
|
60
|
+
const props = defineProps({
|
|
61
|
+
/**
|
|
62
|
+
* The password input's model value
|
|
63
|
+
* @type {String|Number}
|
|
64
|
+
*/
|
|
65
|
+
modelValue: [String, Number],
|
|
66
|
+
/**
|
|
67
|
+
* Hide password strength requirements display
|
|
68
|
+
* @type {Boolean}
|
|
69
|
+
*/
|
|
70
|
+
hideRequirements: Boolean,
|
|
71
|
+
/**
|
|
72
|
+
* Require at least one lowercase letter
|
|
73
|
+
* @type {Boolean}
|
|
74
|
+
*/
|
|
75
|
+
lowerCase: Boolean,
|
|
76
|
+
/**
|
|
77
|
+
* Require at least one uppercase letter
|
|
78
|
+
* @type {Boolean}
|
|
79
|
+
*/
|
|
80
|
+
upperCase: Boolean,
|
|
81
|
+
/**
|
|
82
|
+
* Require at least one special character (!@#$%^&*)
|
|
83
|
+
* @type {Boolean}
|
|
84
|
+
*/
|
|
85
|
+
specialChar: Boolean,
|
|
86
|
+
/**
|
|
87
|
+
* Require at least one number
|
|
88
|
+
* @type {Boolean}
|
|
89
|
+
*/
|
|
90
|
+
number: Boolean,
|
|
91
|
+
/**
|
|
92
|
+
* Minimum password length requirement
|
|
93
|
+
* @type {Number}
|
|
94
|
+
* @default 8
|
|
95
|
+
*/
|
|
96
|
+
minLength: {
|
|
97
|
+
type: Number,
|
|
98
|
+
default: 8
|
|
95
99
|
},
|
|
100
|
+
/**
|
|
101
|
+
* HTML autocomplete attribute value
|
|
102
|
+
* @type {String}
|
|
103
|
+
*/
|
|
104
|
+
autocomplete: String
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const emit = defineEmits([
|
|
108
|
+
/**
|
|
109
|
+
* Emitted when the password value changes
|
|
110
|
+
* @param {String} value - The updated password value
|
|
111
|
+
*/
|
|
112
|
+
'update:modelValue',
|
|
113
|
+
/**
|
|
114
|
+
* Emitted when password strength changes
|
|
115
|
+
* @param {Object} strengthData - Password strength information
|
|
116
|
+
* @param {Number} strengthData.strength - Password strength score (0-100)
|
|
117
|
+
* @param {Number} strengthData.level - Password strength level (0-4)
|
|
118
|
+
*/
|
|
119
|
+
'strength-change'
|
|
120
|
+
])
|
|
121
|
+
|
|
122
|
+
// Reactive data
|
|
123
|
+
const lazyValue = ref(props.modelValue || '')
|
|
124
|
+
const show = ref(false)
|
|
125
|
+
const active = ref(false)
|
|
126
|
+
const inputRef = ref(null)
|
|
127
|
+
|
|
128
|
+
// Computed properties - Password requirement checks
|
|
129
|
+
/**
|
|
130
|
+
* Checks if password meets minimum length requirement
|
|
131
|
+
* @returns {Boolean} True if password meets length requirement
|
|
132
|
+
*/
|
|
133
|
+
const hasLength = computed(() => {
|
|
134
|
+
if (!lazyValue.value) return false
|
|
135
|
+
return lazyValue.value.length >= props.minLength
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Checks if password contains at least one uppercase letter
|
|
140
|
+
* @returns {Boolean} True if password contains uppercase letter
|
|
141
|
+
*/
|
|
142
|
+
const hasUpperCase = computed(() => {
|
|
143
|
+
if (!lazyValue.value) return false
|
|
144
|
+
return /[A-Z]/.test(lazyValue.value)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Checks if password contains at least one number
|
|
149
|
+
* @returns {Boolean} True if password contains number
|
|
150
|
+
*/
|
|
151
|
+
const hasNumber = computed(() => {
|
|
152
|
+
if (!lazyValue.value) return false
|
|
153
|
+
return /[0-9]/.test(lazyValue.value)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Checks if password contains at least one lowercase letter
|
|
158
|
+
* @returns {Boolean} True if password contains lowercase letter
|
|
159
|
+
*/
|
|
160
|
+
const hasLowerCase = computed(() => {
|
|
161
|
+
if (!lazyValue.value) return false
|
|
162
|
+
return /[a-z]/.test(lazyValue.value)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Checks if password contains at least one special character
|
|
167
|
+
* @returns {Boolean} True if password contains special character
|
|
168
|
+
*/
|
|
169
|
+
const hasSpecialChar = computed(() => {
|
|
170
|
+
if (!lazyValue.value) return false
|
|
171
|
+
return /[!@#$%^&*]/.test(lazyValue.value)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
// Computed properties
|
|
175
|
+
/**
|
|
176
|
+
* Calculates password strength score (0-100)
|
|
177
|
+
* @returns {Number} Password strength score
|
|
178
|
+
*/
|
|
179
|
+
const passwordStrength = computed(() => {
|
|
180
|
+
if (!lazyValue.value) return 0
|
|
181
|
+
|
|
182
|
+
let score = 0
|
|
183
|
+
const length = lazyValue.value.length
|
|
184
|
+
score += Math.min(40, (length / 128) * 40)
|
|
185
|
+
|
|
186
|
+
const varietyCount = [hasLowerCase.value, hasUpperCase.value, hasNumber.value, hasSpecialChar.value].filter(Boolean).length
|
|
187
|
+
score += (varietyCount / 4) * 40
|
|
188
|
+
|
|
189
|
+
if (length >= 12 && varietyCount >= 3) score += 20
|
|
190
|
+
|
|
191
|
+
return Math.min(100, score)
|
|
192
|
+
})
|
|
96
193
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Determines CSS color class based on password strength
|
|
196
|
+
* @returns {String} CSS color class for strength indicator
|
|
197
|
+
*/
|
|
198
|
+
const strengthColor = computed(() => {
|
|
199
|
+
const strength = passwordStrength.value
|
|
200
|
+
|
|
201
|
+
if (strength >= 80) return 'color-success'
|
|
202
|
+
if (strength >= 60) return 'color-info'
|
|
203
|
+
if (strength >= 40) return 'color-warning'
|
|
204
|
+
return 'color-error'
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Determines password strength level (0-4)
|
|
209
|
+
* @returns {Number} Password strength level
|
|
210
|
+
*
|
|
211
|
+
* Levels:
|
|
212
|
+
* - 0: No password or very weak
|
|
213
|
+
* - 1: Weak (score > 0)
|
|
214
|
+
* - 2: Fair (score >= 40)
|
|
215
|
+
* - 3: Good (score >= 60)
|
|
216
|
+
* - 4: Strong (score >= 80)
|
|
217
|
+
*/
|
|
218
|
+
const strengthLevel = computed(() => {
|
|
219
|
+
const strength = passwordStrength.value
|
|
220
|
+
|
|
221
|
+
if (strength >= 80) return 4
|
|
222
|
+
if (strength >= 60) return 3
|
|
223
|
+
if (strength >= 40) return 2
|
|
224
|
+
if (strength > 0) return 1
|
|
225
|
+
return 0
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Checks if password meets all configured requirements
|
|
230
|
+
* @returns {Boolean} True if password is valid according to all requirements
|
|
231
|
+
*/
|
|
232
|
+
const isValid = computed(() => {
|
|
233
|
+
let valid = true
|
|
234
|
+
if (!hasLength.value) valid = false
|
|
235
|
+
if (props.lowerCase && !hasLowerCase.value) valid = false
|
|
236
|
+
if (props.upperCase && !hasUpperCase.value) valid = false
|
|
237
|
+
if (props.number && !hasNumber.value) valid = false
|
|
238
|
+
if (props.specialChar && !hasSpecialChar.value) valid = false
|
|
239
|
+
|
|
240
|
+
return valid
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
// Methods
|
|
244
|
+
/**
|
|
245
|
+
* Focuses the password input field
|
|
246
|
+
*/
|
|
247
|
+
const handleClick = () => {
|
|
248
|
+
inputRef.value?.focus()
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Emits updated password value and strength data
|
|
253
|
+
*/
|
|
254
|
+
const emitValue = () => {
|
|
255
|
+
emit('update:modelValue', lazyValue.value)
|
|
256
|
+
emit('strength-change', {
|
|
257
|
+
strength: passwordStrength.value,
|
|
258
|
+
level: strengthLevel.value
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Toggles password visibility and refocuses input
|
|
264
|
+
*/
|
|
265
|
+
const toggleShow = () => {
|
|
266
|
+
show.value = !show.value
|
|
267
|
+
nextTick(() => inputRef.value?.focus())
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Watchers
|
|
271
|
+
watch(() => props.modelValue, (newValue) => {
|
|
272
|
+
lazyValue.value = newValue || ''
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
watch(lazyValue, () => {
|
|
276
|
+
emitValue()
|
|
277
|
+
})
|
|
278
|
+
</script>
|
|
279
|
+
<style lang="scss">
|
|
280
|
+
@use "../../../style" as *;
|
|
281
|
+
|
|
282
|
+
.#{$prefix}password-input {
|
|
283
|
+
.msg-item {
|
|
284
|
+
display: flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
|
|
287
|
+
svg {
|
|
288
|
+
width: 20px;
|
|
289
|
+
height: 20px;
|
|
126
290
|
}
|
|
127
291
|
}
|
|
128
|
-
}
|
|
129
292
|
|
|
130
|
-
|
|
293
|
+
.massage {
|
|
294
|
+
display: block;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
</style>
|
|
@@ -1,107 +1,178 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<r-input
|
|
3
|
-
:modelValue="modelValue"
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<r-input :class="[`${$r.prefix}radio-input`]"
|
|
3
|
+
:modelValue="modelValue"
|
|
4
|
+
label-active>
|
|
5
|
+
<div v-for="(item,i) in list"
|
|
6
|
+
:key="i"
|
|
7
|
+
:class="{'radio-item-selected':current===item.value}" class="radio-item my-2">
|
|
8
|
+
<!-- Custom slot for radio item rendering with emit function, index, and item data -->
|
|
9
|
+
<slot :emit="emitValue" :index="i" :item="item">
|
|
6
10
|
<span class="radio-input-item" :class="{
|
|
7
11
|
'br-circle':rounded,
|
|
8
12
|
'radio-input-select':current===item.value
|
|
9
|
-
}" @click.prevent="
|
|
10
|
-
|
|
11
|
-
<r-icon v-if="current===item.value" class="color-white-text"
|
|
12
|
-
v-html="$r.icons.check" exact></r-icon>
|
|
13
|
-
</transition>
|
|
14
|
-
</span>
|
|
15
|
-
<span class="ms-2 radio-label" @click.prevent="emit(item)">
|
|
13
|
+
}" @click.prevent="emitValue(item)"></span>
|
|
14
|
+
<span class="ms-2 radio-label" @click.prevent="emitValue(item)">
|
|
16
15
|
{{ item[text] }}
|
|
17
16
|
</span>
|
|
17
|
+
</slot>
|
|
18
18
|
</div>
|
|
19
19
|
</r-input>
|
|
20
20
|
</template>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
|
|
22
|
+
<script setup>
|
|
23
|
+
import {computed, inject} from 'vue'
|
|
24
|
+
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
/**
|
|
27
|
+
* Array of radio items (objects or primitives)
|
|
28
|
+
* @type {Array}
|
|
29
|
+
* @default () => []
|
|
30
|
+
*
|
|
31
|
+
* If objects, each should have at least a 'value' property and optionally a text property
|
|
32
|
+
* If primitives, they will be converted to objects with value and text properties
|
|
33
|
+
*/
|
|
34
|
+
items: {
|
|
35
|
+
type: Array,
|
|
36
|
+
default: () => []
|
|
36
37
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
list() {
|
|
46
|
-
const l = this.items.length
|
|
47
|
-
if (typeof this.items[0] === 'object') {
|
|
48
|
-
return this.items
|
|
49
|
-
}
|
|
50
|
-
let r = []
|
|
51
|
-
for (let i = 0; i < l; i++) {
|
|
52
|
-
r.push({[this.text]: this.translate ? $t(this.items[i]) : this.items[i], 'value': this.items[i]})
|
|
53
|
-
}
|
|
54
|
-
return r
|
|
55
|
-
}
|
|
38
|
+
/**
|
|
39
|
+
* Property name to use for display text in items
|
|
40
|
+
* @type {String}
|
|
41
|
+
* @default 'title'
|
|
42
|
+
*/
|
|
43
|
+
text: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: 'title'
|
|
56
46
|
},
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Use circular radio buttons instead of square
|
|
49
|
+
* @type {Boolean}
|
|
50
|
+
*/
|
|
51
|
+
rounded: Boolean,
|
|
52
|
+
/**
|
|
53
|
+
* Emit only the value instead of the entire item object
|
|
54
|
+
* @type {Boolean}
|
|
55
|
+
*/
|
|
56
|
+
justValue: Boolean,
|
|
57
|
+
/**
|
|
58
|
+
* Enable translation for item texts
|
|
59
|
+
* @type {Boolean}
|
|
60
|
+
*/
|
|
61
|
+
translate: Boolean,
|
|
62
|
+
/**
|
|
63
|
+
* The selected radio item's model value
|
|
64
|
+
* @type {String|Number|Object}
|
|
65
|
+
*/
|
|
66
|
+
modelValue: [String, Number, Object]
|
|
67
|
+
})
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
const emit = defineEmits([
|
|
70
|
+
/**
|
|
71
|
+
* Emitted when a radio item is selected
|
|
72
|
+
* @param {Object|String|Number} value - Selected item or value
|
|
73
|
+
*
|
|
74
|
+
* When justValue is true: emits the item's value property
|
|
75
|
+
* When justValue is false: emits the entire item object
|
|
76
|
+
*/
|
|
77
|
+
'update:modelValue'
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
const {$t} = inject('renusify')
|
|
81
|
+
|
|
82
|
+
// Computed properties
|
|
83
|
+
/**
|
|
84
|
+
* Gets the current selected value for comparison
|
|
85
|
+
* @returns {String|Number|null} Current selected value or null if none
|
|
86
|
+
*/
|
|
87
|
+
const current = computed(() => {
|
|
88
|
+
if (!props.modelValue) {
|
|
89
|
+
return null
|
|
90
|
+
}
|
|
91
|
+
return props.justValue ? props.modelValue : props.modelValue.value
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Processes items array for consistent format
|
|
96
|
+
* @returns {Array} Processed list of radio items
|
|
97
|
+
*
|
|
98
|
+
* Converts primitive values to objects with {text, value} structure
|
|
99
|
+
* Applies translation if enabled
|
|
100
|
+
*/
|
|
101
|
+
const list = computed(() => {
|
|
102
|
+
const l = props.items.length
|
|
103
|
+
if (typeof props.items[0] === 'object') {
|
|
104
|
+
return props.items
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let r = []
|
|
108
|
+
for (let i = 0; i < l; i++) {
|
|
109
|
+
r.push({
|
|
110
|
+
[props.text]: props.translate ? $t(props.items[i]) : props.items[i],
|
|
111
|
+
'value': props.items[i]
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
return r
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Methods
|
|
118
|
+
/**
|
|
119
|
+
* Emits the selected radio item
|
|
120
|
+
* @param {Object} val - The selected radio item
|
|
121
|
+
*/
|
|
122
|
+
const emitValue = (val) => {
|
|
123
|
+
if (props.readonly) {
|
|
124
|
+
return
|
|
65
125
|
}
|
|
66
|
-
}
|
|
67
126
|
|
|
127
|
+
emit('update:modelValue', props.justValue ? val.value : val)
|
|
128
|
+
}
|
|
68
129
|
</script>
|
|
130
|
+
|
|
69
131
|
<style lang="scss">
|
|
70
132
|
@use "sass:map";
|
|
71
|
-
@use "../../../style
|
|
72
|
-
|
|
133
|
+
@use "../../../style" as *;
|
|
73
134
|
|
|
74
|
-
.#{
|
|
135
|
+
.#{$prefix}radio-input {
|
|
75
136
|
width: 100%;
|
|
76
137
|
cursor: pointer;
|
|
77
138
|
|
|
139
|
+
.input-control {
|
|
140
|
+
height: auto;
|
|
141
|
+
}
|
|
142
|
+
|
|
78
143
|
.radio-label {
|
|
79
144
|
color: var(--color-on-sheet);
|
|
80
145
|
}
|
|
81
146
|
|
|
82
|
-
.radio-
|
|
83
|
-
|
|
147
|
+
.radio-item {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
84
150
|
}
|
|
85
151
|
|
|
86
|
-
|
|
152
|
+
.radio-input-item {
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: center;
|
|
87
156
|
width: 20px;
|
|
88
157
|
height: 20px;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
text-align: center;
|
|
93
|
-
width: 25px;
|
|
94
|
-
height: 25px;
|
|
95
|
-
border-radius: map.get(base.$borders, 'sm');
|
|
96
|
-
transition: .3s all ease-in-out;
|
|
97
|
-
}
|
|
158
|
+
border-radius: map.get($borders, 'sm');
|
|
159
|
+
transition: all $primary-transition;
|
|
160
|
+
border: 1px solid var(--color-on-sheet-low);
|
|
98
161
|
|
|
99
|
-
|
|
100
|
-
|
|
162
|
+
&::before {
|
|
163
|
+
content: '';
|
|
164
|
+
display: inline-block;
|
|
165
|
+
width: 12px;
|
|
166
|
+
height: 12px;
|
|
167
|
+
border-radius: inherit;
|
|
168
|
+
background-color: currentColor;
|
|
169
|
+
opacity: 0;
|
|
170
|
+
transition: all $primary-transition;
|
|
171
|
+
}
|
|
101
172
|
}
|
|
102
173
|
|
|
103
|
-
.radio-input-select {
|
|
104
|
-
|
|
174
|
+
.radio-input-select::before {
|
|
175
|
+
opacity: 1;
|
|
105
176
|
}
|
|
106
177
|
}
|
|
107
178
|
</style>
|