renusify 2.5.1 → 3.0.0

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.
Files changed (212) hide show
  1. package/components/app/index.vue +74 -22
  2. package/components/app/toast/index.vue +76 -71
  3. package/components/app/toast/toast.vue +62 -44
  4. package/components/avatar/index.vue +208 -84
  5. package/components/button/buttonConfirm.vue +53 -26
  6. package/components/button/buttonGroup.js +0 -2
  7. package/components/button/buttonGroup.vue +310 -62
  8. package/components/button/index.vue +584 -100
  9. package/components/calendar/index.js +0 -2
  10. package/components/calendar/index.vue +326 -262
  11. package/components/calendar/month.vue +64 -55
  12. package/components/calendar/year.vue +30 -25
  13. package/components/card/index.vue +139 -59
  14. package/components/codeEditor/highlightCss.vue +38 -39
  15. package/components/codeEditor/highlightHtml.vue +64 -64
  16. package/components/codeEditor/highlightJs.vue +37 -38
  17. package/components/codeEditor/index.vue +129 -79
  18. package/components/codeEditor/run.vue +225 -39
  19. package/components/codeEditor/useCodeFormatter.js +150 -0
  20. package/components/confirm/index.vue +140 -81
  21. package/components/container/col.vue +5 -4
  22. package/components/container/divider.vue +28 -19
  23. package/components/container/index.vue +34 -15
  24. package/components/container/row.vue +26 -9
  25. package/components/container/spacer.vue +2 -4
  26. package/components/container/style.scss +3 -0
  27. package/components/content/index.vue +49 -32
  28. package/components/cropper/index.vue +401 -244
  29. package/components/float/index.vue +542 -415
  30. package/components/form/addressInput/index.vue +184 -109
  31. package/components/form/camInput/index.vue +370 -244
  32. package/components/form/checkInput/index.vue +138 -71
  33. package/components/form/checkboxInput/index.vue +87 -47
  34. package/components/form/colorInput/Alpha.vue +81 -83
  35. package/components/form/colorInput/Hue.vue +91 -68
  36. package/components/form/colorInput/Preview.vue +43 -47
  37. package/components/form/colorInput/Saturation.vue +101 -86
  38. package/components/form/colorInput/index.vue +72 -40
  39. package/components/form/colorInput/picker.vue +111 -106
  40. package/components/form/colorInput/useColor.js +153 -0
  41. package/components/form/dateInput/index.vue +691 -356
  42. package/components/form/dateInput/month.vue +63 -54
  43. package/components/form/dateInput/year.vue +35 -25
  44. package/components/form/fileInput/index.js +0 -1
  45. package/components/form/fileInput/index.vue +263 -106
  46. package/components/form/fileInput/single.vue +323 -164
  47. package/components/form/groupInput/index.vue +199 -101
  48. package/components/form/index.vue +189 -83
  49. package/components/form/input/index.vue +416 -377
  50. package/components/form/jsonInput/JsonView.vue +54 -56
  51. package/components/form/jsonInput/index.vue +247 -165
  52. package/components/form/maskInput/index.vue +252 -132
  53. package/components/form/numberInput/index.js +0 -1
  54. package/components/form/numberInput/index.vue +226 -117
  55. package/components/form/passwordInput/index.js +2 -1
  56. package/components/form/passwordInput/index.vue +269 -102
  57. package/components/form/radioInput/index.vue +143 -72
  58. package/components/form/rangeInput/index.vue +280 -167
  59. package/components/form/ratingInput/index.vue +57 -57
  60. package/components/form/selectInput/index.js +1 -3
  61. package/components/form/selectInput/index.vue +584 -296
  62. package/components/form/switchInput/index.vue +73 -59
  63. package/components/form/telInput/index.js +0 -1
  64. package/components/form/telInput/index.vue +238 -135
  65. package/components/form/textArea/index.vue +72 -35
  66. package/components/form/textEditor/index.vue +739 -0
  67. package/components/form/{text-editor → textEditor}/style.scss +8 -16
  68. package/components/form/textInput/index.vue +54 -32
  69. package/components/form/timeInput/index.vue +83 -56
  70. package/components/form/timeInput/range.vue +116 -95
  71. package/components/form/timeInput/timepicker.vue +382 -449
  72. package/components/form/uniqueInput/index.vue +105 -48
  73. package/components/form/unitInput/index.vue +139 -84
  74. package/components/formCreator/index.js +0 -1
  75. package/components/formCreator/index.vue +314 -148
  76. package/components/highlight/index.vue +41 -25
  77. package/components/highlight/style.scss +2 -2
  78. package/components/highlight/{mixin.js → useHighlight.js} +181 -160
  79. package/components/icon/index.vue +79 -33
  80. package/components/img/index.vue +249 -147
  81. package/components/img/preview.vue +180 -198
  82. package/components/img/svgImg.vue +42 -39
  83. package/components/index.js +5 -20
  84. package/components/infinite/index.js +1 -2
  85. package/components/infinite/index.vue +248 -66
  86. package/components/map/index.vue +428 -261
  87. package/components/map/route.vue +794 -487
  88. package/components/map/select.vue +118 -58
  89. package/components/menu/index.vue +201 -91
  90. package/components/meta/meta.js +26 -3
  91. package/components/modal/index.vue +383 -158
  92. package/components/notify/index.vue +204 -86
  93. package/components/notify/notification.vue +38 -55
  94. package/components/progress/circle.vue +189 -70
  95. package/components/progress/line.vue +266 -46
  96. package/components/searchBox/index.js +1 -3
  97. package/components/searchBox/index.vue +194 -101
  98. package/components/skeleton/index.vue +45 -20
  99. package/components/slider/index.vue +318 -156
  100. package/components/swiper/index.vue +254 -106
  101. package/components/table/crud/footer.vue +77 -53
  102. package/components/table/crud/header.vue +71 -72
  103. package/components/table/crud/index.vue +631 -401
  104. package/components/table/index.vue +721 -278
  105. package/components/timeAgo/index.vue +145 -96
  106. package/components/tour/index.vue +338 -235
  107. package/components/tree/index.vue +235 -89
  108. package/components/tree/tree-element.vue +107 -106
  109. package/directive/animate/index.js +77 -0
  110. package/directive/clickOutSide/index.js +98 -0
  111. package/directive/drag/index.js +153 -0
  112. package/directive/index.js +11 -13
  113. package/directive/intersect/index.js +263 -0
  114. package/directive/mask/index.js +67 -0
  115. package/directive/parallax/index.js +78 -0
  116. package/directive/ripple/index.js +14 -0
  117. package/directive/scroll/index.js +244 -0
  118. package/directive/sortable/index.js +274 -0
  119. package/directive/title/index.js +75 -0
  120. package/directive/touch/index.js +268 -0
  121. package/index.js +10 -8
  122. package/package.json +5 -2
  123. package/plugins/validation/Validate.js +88 -79
  124. package/scripts/generate-docs.mjs +226 -0
  125. package/scripts/menu.mjs +240 -0
  126. package/scripts/parser.mjs +1086 -0
  127. package/style/_index.scss +7 -0
  128. package/style/app.scss +13 -65
  129. package/style/colors.scss +5 -22
  130. package/style/functions/index.scss +8 -0
  131. package/style/mixins/index.scss +17 -5
  132. package/style/variables/base.scss +154 -175
  133. package/style/variables/color.scss +0 -12
  134. package/style/variables/utilities.scss +0 -180
  135. package/tools/helper.js +0 -8
  136. package/tools/icons.js +6 -1
  137. package/tools/root.js +71 -0
  138. package/components/app/style.scss +0 -41
  139. package/components/app/toast/style.scss +0 -20
  140. package/components/avatar/style.scss +0 -32
  141. package/components/bar/bottomNav.js +0 -1
  142. package/components/bar/bottomNav.vue +0 -28
  143. package/components/bar/bottomNavigationCircle.js +0 -2
  144. package/components/bar/bottomNavigationCircle.vue +0 -99
  145. package/components/bar/scss/bottomNav.scss +0 -67
  146. package/components/bar/scss/toolbar.scss +0 -174
  147. package/components/bar/toolbar/index.js +0 -8
  148. package/components/bar/toolbar/index.vue +0 -35
  149. package/components/bar/toolbar/laptop.vue +0 -33
  150. package/components/bar/toolbar/menuChilds.vue +0 -41
  151. package/components/bar/toolbar/menuLaptop.vue +0 -41
  152. package/components/bar/toolbar/menuMob.vue +0 -39
  153. package/components/bar/toolbar/mixin.js +0 -43
  154. package/components/bar/toolbar/mobile.vue +0 -34
  155. package/components/breadcrumb/bredcrumbItem.vue +0 -39
  156. package/components/breadcrumb/index.js +0 -3
  157. package/components/breadcrumb/index.vue +0 -71
  158. package/components/breadcrumb/style.scss +0 -51
  159. package/components/button/style.scss +0 -411
  160. package/components/card/style.scss +0 -86
  161. package/components/chart/chart.js +0 -1
  162. package/components/chart/chart.vue +0 -69
  163. package/components/chart/worldMap.js +0 -2
  164. package/components/chart/worldMap.vue +0 -1112
  165. package/components/chat/MessageList.vue +0 -163
  166. package/components/chat/chatInput.vue +0 -150
  167. package/components/chat/chatMsg.vue +0 -276
  168. package/components/chat/index.js +0 -11
  169. package/components/chat/index.vue +0 -113
  170. package/components/chip/index.js +0 -3
  171. package/components/chip/index.vue +0 -77
  172. package/components/chip/style.scss +0 -199
  173. package/components/codeEditor/mixin.js +0 -145
  174. package/components/countdown/index.js +0 -1
  175. package/components/countdown/index.vue +0 -105
  176. package/components/form/colorInput/mixin.js +0 -132
  177. package/components/form/fileInput/file.js +0 -148
  178. package/components/form/telInput/assets/flags.png +0 -0
  179. package/components/form/telInput/assets/flags@2x.png +0 -0
  180. package/components/form/text-editor/index.vue +0 -710
  181. package/components/icon/style.scss +0 -17
  182. package/components/infinite/div.js +0 -6
  183. package/components/infinite/div.vue +0 -193
  184. package/components/infinite/page.js +0 -3
  185. package/components/infinite/page.vue +0 -105
  186. package/components/list/index.js +0 -3
  187. package/components/list/index.vue +0 -122
  188. package/components/list/style.scss +0 -66
  189. package/components/message/index.js +0 -4
  190. package/components/message/index.vue +0 -40
  191. package/components/modal/style.scss +0 -146
  192. package/components/nestable/NestableItem.vue +0 -307
  193. package/components/nestable/editable.js +0 -44
  194. package/components/nestable/index.js +0 -1
  195. package/components/nestable/index.vue +0 -226
  196. package/components/nestable/methods.js +0 -416
  197. package/components/progress/style.scss +0 -229
  198. package/components/table/style.scss +0 -338
  199. package/components/tabs/index.js +0 -3
  200. package/components/tabs/index.vue +0 -151
  201. package/components/timeline/index.js +0 -6
  202. package/components/timeline/index.vue +0 -76
  203. package/directive/resize/index.js +0 -30
  204. package/directive/skeleton/index.js +0 -27
  205. package/directive/skeleton/style.scss +0 -37
  206. package/plugins/request/Request.js +0 -68
  207. package/style/animation.scss +0 -94
  208. package/style/style.scss +0 -8
  209. package/tools/rootable.js +0 -75
  210. /package/components/form/{text-editor → textEditor}/index.js +0 -0
  211. /package/components/form/{text-editor → textEditor}/preview.js +0 -0
  212. /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
@@ -1,130 +1,297 @@
1
1
  <template>
2
- <div :class="$r.prefix+'password'">
3
- <r-input v-bind="$attrs"
4
- :active="active"
5
- :model-value="modelValue"
6
- @click.prevent="handleClick"
7
- :error="errorState"
8
- :preIcon="show?$r.icons.eye_off:$r.icons.eye"
9
- ltr
10
- @preIcon="show=!show"
11
- >
12
- <input :autofocus="autofocus"
13
- :type="show?'text':'password'"
14
- class="pb-0"
15
- @focusin="active=true"
16
- @focusout="active=false"
17
- @input="emit"
18
- :autocomplete="autocomplete"
19
- ref="input"
20
- v-model="lazyValue"
21
- />
22
- </r-input>
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
- </div>
51
+ </r-input>
51
52
  </template>
52
- <script>
53
- export default {
54
- name: 'r-password',
55
- props: {
56
- modelValue: [String, Number],
57
- hideLine: Boolean,
58
- autofocus: Boolean,
59
- lowerCase: {type: Boolean, default: true},
60
- upperCase: Boolean,
61
- specialChar: Boolean,
62
- number: Boolean,
63
- minLength: {type: Number, default: 8},
64
- autocomplete: {type: String, default: "no"},
65
- },
66
- emits: ['update:modelValue'],
67
- data() {
68
- return {
69
- lazyValue: this.modelValue,
70
- show: false,
71
- active: false,
72
- p: 0,
73
- errorState: false
74
- }
75
- },
76
- computed: {
77
- hasLength() {
78
- if (!this.lazyValue) {
79
- return false
80
- }
81
- return this.lazyValue.length >= this.minLength
82
- },
83
- hasUpperCase() {
84
- return new RegExp("^(?=.*[A-Z])").test(this.lazyValue)
85
- },
86
- hasNumber() {
87
- return new RegExp("^(?=.*[0-9])").test(this.lazyValue)
88
- },
89
- hasLowerCase() {
90
- return new RegExp("^(?=.*[a-z])").test(this.lazyValue)
91
- },
92
- hasSpecialChar() {
93
- return new RegExp("^(?=.*[!@#\$%\^&\*])").test(this.lazyValue)
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
- methods: {
98
- check() {
99
- if (!this.hasLength) {
100
- this.errorState = true
101
- }
102
- if (this.lowerCase && !this.hasLowerCase) {
103
- this.errorState = true
104
- }
105
- if (this.number && !this.hasNumber) {
106
- this.errorState = true
107
- }
108
- if (this.upperCase && !this.hasUpperCase) {
109
- this.errorState = true
110
- }
111
- if (this.specialChar && !this.hasSpecialChar) {
112
- this.errorState = true
113
- }
114
-
115
- },
116
- handleClick(e) {
117
- this.$refs.input.focus()
118
- },
119
- emit() {
120
- this.$emit('update:modelValue', this.lazyValue)
121
- this.errorState = false
122
- this.msg = null
123
- if (this.lazyValue && !this.hideLine) {
124
- this.check()
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
- </script>
293
+ .massage {
294
+ display: block;
295
+ }
296
+ }
297
+ </style>
@@ -1,107 +1,178 @@
1
1
  <template>
2
- <r-input class="mt-3" :class="{[`${this.$r.prefix}radio-input`]:true,'radio-input-readonly': readonly}"
3
- :modelValue="modelValue" hide labelControlClass="label-fixed">
4
- <div class="mt-2" v-for="(item,i) in list" :key="i"
5
- :class="{'d-flex v-end': true}">
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="emit(item)">
10
- <transition name="scale">
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
- <script>
22
- export default {
23
- name: 'r-radio-input',
24
- props: {
25
- items: {
26
- type: Array, default: () => {
27
- return []
28
- }
29
- },
30
- text: {type: String, default: 'title'},
31
- readonly: Boolean,
32
- rounded: Boolean,
33
- justValue: Boolean,
34
- translate: Boolean,
35
- modelValue: [String, Number, Object]
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
- emits: ['update:modelValue'],
38
- computed: {
39
- current() {
40
- if (!this.modelValue) {
41
- return null
42
- }
43
- return this.justValue ? this.modelValue : this.modelValue.value
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
- methods: {
58
- emit(val) {
59
- if (this.readonly) {
60
- return
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
- this.$emit('update:modelValue', this.justValue ? val.value : val)
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/variables/base";
72
-
133
+ @use "../../../style" as *;
73
134
 
74
- .#{base.$prefix}radio-input {
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-input-item {
83
- border: 1px solid var(--color-on-sheet-low)
147
+ .radio-item {
148
+ display: flex;
149
+ align-items: center;
84
150
  }
85
151
 
86
- .#{base.$prefix}icon {
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
- .radio-input-item {
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
- &.radio-input-readonly {
100
- pointer-events: none;
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
- background-color: currentColor;
174
+ .radio-input-select::before {
175
+ opacity: 1;
105
176
  }
106
177
  }
107
178
  </style>