@verdnatura/vn-front-lib 0.0.2
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/LICENSE +17 -0
- package/README.md +75 -0
- package/dist/components-C4qIWgU6.cjs +1 -0
- package/dist/components-Ct0VDaxz.js +316 -0
- package/dist/components.cjs +1 -0
- package/dist/components.js +2 -0
- package/dist/composables.cjs +1 -0
- package/dist/composables.js +2 -0
- package/dist/stores.cjs +1 -0
- package/dist/stores.js +2 -0
- package/dist/useRequired-BDeZirAF.js +58 -0
- package/dist/useRequired-I81Vonhu.cjs +1 -0
- package/dist/useValidationsStore-B5R8zW5O.js +19 -0
- package/dist/useValidationsStore-CmGCLBNO.cjs +1 -0
- package/dist/vn-front-lib.cjs +1 -0
- package/dist/vn-front-lib.css +2 -0
- package/dist/vn-front-lib.js +12 -0
- package/lib/components/index.js +1 -0
- package/lib/components/inputs/VnInput.vue +243 -0
- package/lib/composables/index.js +2 -0
- package/lib/composables/useRequired.js +15 -0
- package/lib/composables/useValidator.js +94 -0
- package/lib/config.js +16 -0
- package/lib/i18n/locale/en.yml +4 -0
- package/lib/i18n/locale/es.yml +4 -0
- package/lib/main.js +16 -0
- package/lib/stores/index.js +1 -0
- package/lib/stores/useValidationsStore.js +14 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Copyright (C) 2026 - Verdnatura Levante S.L.
|
|
2
|
+
|
|
3
|
+
This package is free software; you can redistribute it and/or modify
|
|
4
|
+
it under the terms of the GNU General Public License as published by
|
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
(at your option) any later version.
|
|
7
|
+
|
|
8
|
+
This program is distributed in the hope that it will be useful,
|
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
GNU General Public License for more details.
|
|
12
|
+
|
|
13
|
+
You should have received a copy of the GNU General Public License
|
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
On Debian systems, the complete text of the GNU General Public
|
|
17
|
+
License can be found in "/usr/share/common-licenses/GPL-3".
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# vn-front-lib
|
|
2
|
+
|
|
3
|
+
A shared library of Vue 3 components and composables used across the
|
|
4
|
+
**salix-front** and **hedera-web** projects. It is not a standalone app —
|
|
5
|
+
it's built in library mode (Vite `build.lib`) and consumed as a dependency.
|
|
6
|
+
|
|
7
|
+
## What's inside
|
|
8
|
+
|
|
9
|
+
- `lib/components/` — Vue components (prefixed with `Vn`, e.g. `VnInput`).
|
|
10
|
+
- `lib/composables/` — reusable composables (e.g. `useRequired`, `useValidator`).
|
|
11
|
+
- `lib/stores/` — Pinia stores (e.g. `useValidationsStore`).
|
|
12
|
+
- `lib/config.js` — internal library config, filled via `setConfig()` from the
|
|
13
|
+
`options` passed to `app.use(VnFrontLib, options)` (`axios` is required).
|
|
14
|
+
- `lib/i18n/locale/` — translation files (`en.yml`, `es.yml`).
|
|
15
|
+
|
|
16
|
+
`pinia`, `vue-i18n`, `axios`, `validator` and `quasar` are expected to be
|
|
17
|
+
provided by the consuming project (declared as `peerDependencies`).
|
|
18
|
+
|
|
19
|
+
## Recommended VS Code extension
|
|
20
|
+
|
|
21
|
+
This project uses [oxlint](https://oxc.rs/docs/guide/usage/linter.html) and
|
|
22
|
+
[oxfmt](https://oxc.rs/docs/guide/usage/formatter.html) for linting and
|
|
23
|
+
formatting. It's advisable to install the
|
|
24
|
+
[Oxc VS Code extension](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode),
|
|
25
|
+
which powers format-on-save and inline lint diagnostics based on the
|
|
26
|
+
`.oxlintrc.json` and `.oxfmtrc.json` config files in this repo.
|
|
27
|
+
|
|
28
|
+
## Scripts
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm install
|
|
32
|
+
pnpm run dev # Vite dev server
|
|
33
|
+
pnpm run build # build the library (output to dist/)
|
|
34
|
+
pnpm run lint # oxlint
|
|
35
|
+
pnpm run lint:fix # oxlint --fix
|
|
36
|
+
pnpm run fmt # oxfmt
|
|
37
|
+
pnpm run fmt:check # oxfmt --check
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Developing locally against another project
|
|
41
|
+
|
|
42
|
+
To test changes locally in another project (e.g. `salix-front` or
|
|
43
|
+
`hedera-web`) without publishing, add this repo as a real pnpm workspace
|
|
44
|
+
member rather than using a plain `link:` dependency, so `vue`/`pinia` get
|
|
45
|
+
deduped into a single instance across both projects:
|
|
46
|
+
|
|
47
|
+
1. In the consuming project's `pnpm-workspace.yaml`, add this repo as a
|
|
48
|
+
package:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
packages:
|
|
52
|
+
- .
|
|
53
|
+
- ../vn-front-lib
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
2. In the consuming project's `package.json`, depend on it via the workspace
|
|
57
|
+
protocol, using the real package name:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
"vn-front-lib": "workspace:@verdnatura/vn-front-lib@*",
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
3. Enable the `vnSource` resolution condition in the consumer's Vite/Vitest
|
|
64
|
+
config so imports resolve to this repo's `lib/` source instead of the
|
|
65
|
+
`dist/` build:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
resolve: {
|
|
69
|
+
conditions: ['vnSource'],
|
|
70
|
+
},
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. Reinstall dependencies in the consuming project (`pnpm install`), then run
|
|
74
|
+
`pnpm why vue -r` / `pnpm why pinia -r` to confirm only one version of
|
|
75
|
+
each resolves across the workspace.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("./useRequired-I81Vonhu.cjs");let t=require("quasar"),n=require("vue"),r=require("vue-i18n");function i(e){let t=e;t.__i18n=t.__i18n||[],t.__i18n.push({locale:``,resource:{en:{inputMin:{t:0,b:{t:2,i:[{t:3,v:`Must be more than `},{t:4,k:`value`}]}},maxLength:{t:0,b:{t:2,i:[{t:3,v:`The value exceeds `},{t:4,k:`value`},{t:3,v:` characters`}]}},inputMax:{t:0,b:{t:2,i:[{t:3,v:`Must be less than `},{t:4,k:`value`}]}}},es:{inputMin:{t:0,b:{t:2,i:[{t:3,v:`Debe ser mayor a `},{t:4,k:`value`}]}},maxLength:{t:0,b:{t:2,i:[{t:3,v:`El valor excede los `},{t:4,k:`value`},{t:3,v:` carácteres`}]}},inputMax:{t:0,b:{t:2,i:[{t:3,v:`Debe ser menor a `},{t:4,k:`value`}]}},"Convert to uppercase":{t:0,b:{t:2,i:[{t:3}],s:`Convertir a mayúsculas`}},Remove:{t:0,b:{t:2,i:[{t:3}],s:`Eliminar`}}}}})}var a={__name:`VnInput`,props:(0,n.mergeModels)({isOutlined:{type:Boolean,default:!1},info:{type:String,default:``},clearable:{type:Boolean,default:!0},emptyToNull:{type:Boolean,default:!0},insertable:{type:Boolean,default:!1},maxlength:{type:Number,default:null},uppercase:{type:Boolean,default:!1}},{modelValue:{default:null},modelModifiers:{}}),emits:(0,n.mergeModels)([`remove`],[`update:modelValue`]),setup(i,{expose:a,emit:o}){let s=(0,n.useAttrs)(),{isRequired:c,requiredFieldRule:l}=e.t(s),{t:u}=(0,r.useI18n)(),d=o,f=i,p=(0,n.useModel)(i,`modelValue`),m=[`number`,`search`,`tel`,`url`,`password`],h=e=>{let t=e;f.emptyToNull&&t===``&&(t=null),p.value=t},g=(0,n.ref)(null),_=(0,n.ref)(!1),v=(0,n.computed)(()=>f.isOutlined?{dense:!0,outlined:!0,rounded:!0}:{}),y=e=>{g.value?.focus(e)},b=e=>{(0,n.nextTick)(()=>{let t=e.target||g.value?.$el?.querySelector(`input`),n=e.target.type||t?.getAttribute(`type`);if(n!==`email`){if(!m.includes(n)){if(t?.setSelectionRange){let e=t.value?.length??0;t.setSelectionRange(e,e)}return}t?.select?.()}})};a({focus:y,vnInputRef:g});let x=(0,n.computed)(()=>[l,...s.rules??[],e=>{let t=f.maxlength;if(t&&+e?.length>t)return u(`maxLength`,{value:t});let{min:n,max:r}=s,i=n===void 0?void 0:Number(n),a=r===void 0?void 0:Number(r);return i!==void 0&&i>=0&&Math.floor(e)<i?u(`inputMin`,{value:i}):a!==void 0&&a>0&&Math.floor(e)>a?u(`inputMax`,{value:a}):!0}]),S=e=>{e.key!==`Backspace`&&f.insertable&&e.key.match(/[0-9]/)&&C(e)},C=e=>{e.preventDefault();let t=e.target,r=t.selectionStart,i=f.maxlength,a=p.value;a||=e.key;let o=e.key;o&&!isNaN(o)&&r<i&&h(a.substring(0,r)+o+a.substring(r+1)),(0,n.nextTick)(()=>{t.setSelectionRange(r+1,r+1)})},w=()=>{p.value=p.value?.toUpperCase()||``};return(0,n.onMounted)(()=>{s.autofocus&&y()}),(e,r)=>{let a=t.QTooltip,o=t.QIcon,l=t.QInput;return(0,n.openBlock)(),(0,n.createElementBlock)(`div`,{onMouseover:r[1]||=e=>_.value=!0,onMouseleave:r[2]||=e=>_.value=!1},[(0,n.createVNode)(l,(0,n.mergeProps)({ref_key:`vnInputRef`,ref:g,"model-value":(0,n.unref)(p),"onUpdate:modelValue":h},{...(0,n.unref)(s),...v.value},{class:{required:(0,n.unref)(c)},onKeydown:S,onFocus:b,clearable:!1,rules:x.value,"lazy-rules":!0,"hide-bottom-space":``,"data-cy":((0,n.unref)(s)[`data-cy`]??(0,n.unref)(s).label)+`_input`}),(0,n.createSlots)({append:(0,n.withCtx)(()=>[(0,n.createVNode)(o,{name:`close`,size:`xs`,class:`cursor-pointer`,style:(0,n.normalizeStyle)({visibility:_.value&&(0,n.unref)(p)&&!(0,n.unref)(s).disabled&&!(0,n.unref)(s).readonly&&f.clearable?`visible`:`hidden`}),onClick:r[0]||=()=>{h(null),g.value?.focus(),d(`remove`)}},{default:(0,n.withCtx)(()=>[(0,n.createVNode)(a,null,{default:(0,n.withCtx)(()=>[(0,n.createTextVNode)((0,n.toDisplayString)((0,n.unref)(u)(`Remove`)),1)]),_:1})]),_:1},8,[`style`]),!(0,n.unref)(s).disabled&&!(0,n.unref)(s).readonly&&f.uppercase?((0,n.openBlock)(),(0,n.createBlock)(o,{key:0,name:`match_case`,size:`xs`,onClick:w,class:`uppercase-icon`},{default:(0,n.withCtx)(()=>[(0,n.createVNode)(a,null,{default:(0,n.withCtx)(()=>[(0,n.createTextVNode)((0,n.toDisplayString)((0,n.unref)(u)(`Convert to uppercase`)),1)]),_:1})]),_:1})):(0,n.createCommentVNode)(``,!0),e.$slots.append&&!(0,n.unref)(s).disabled?(0,n.renderSlot)(e.$slots,`append`,{},void 0,void 0,1):(0,n.createCommentVNode)(``,!0),i.info?((0,n.openBlock)(),(0,n.createBlock)(o,{key:2,name:`info`},{default:(0,n.withCtx)(()=>[(0,n.createVNode)(a,{"max-width":`350px`},{default:(0,n.withCtx)(()=>[(0,n.createTextVNode)((0,n.toDisplayString)(i.info),1)]),_:1})]),_:1})):(0,n.createCommentVNode)(``,!0)]),_:2},[e.$slots.prepend?{name:`prepend`,fn:(0,n.withCtx)(()=>[(0,n.renderSlot)(e.$slots,`prepend`)]),key:`0`}:void 0]),1040,[`model-value`,`class`,`rules`,`data-cy`])],32)}}};typeof i==`function`&&i(a);var o=e.r({VnInput:()=>a});Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return o}});
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { t as e } from "./useRequired-BDeZirAF.js";
|
|
2
|
+
import { QIcon as t, QInput as n, QTooltip as r } from "quasar";
|
|
3
|
+
import { computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createSlots as c, createTextVNode as l, createVNode as u, mergeModels as d, mergeProps as f, nextTick as p, normalizeStyle as m, onMounted as h, openBlock as g, ref as _, renderSlot as v, toDisplayString as y, unref as b, useAttrs as x, useModel as S, withCtx as C } from "vue";
|
|
4
|
+
import { useI18n as w } from "vue-i18n";
|
|
5
|
+
//#region \0rolldown/runtime.js
|
|
6
|
+
var T = Object.defineProperty, E = (e, t) => {
|
|
7
|
+
let n = {};
|
|
8
|
+
for (var r in e) T(n, r, {
|
|
9
|
+
get: e[r],
|
|
10
|
+
enumerable: !0
|
|
11
|
+
});
|
|
12
|
+
return t || T(n, Symbol.toStringTag, { value: "Module" }), n;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region lib/components/inputs/VnInput.vue?vue&type=i18n&index=0&lang.yaml
|
|
16
|
+
function D(e) {
|
|
17
|
+
let t = e;
|
|
18
|
+
t.__i18n = t.__i18n || [], t.__i18n.push({
|
|
19
|
+
locale: "",
|
|
20
|
+
resource: {
|
|
21
|
+
en: {
|
|
22
|
+
inputMin: {
|
|
23
|
+
t: 0,
|
|
24
|
+
b: {
|
|
25
|
+
t: 2,
|
|
26
|
+
i: [{
|
|
27
|
+
t: 3,
|
|
28
|
+
v: "Must be more than "
|
|
29
|
+
}, {
|
|
30
|
+
t: 4,
|
|
31
|
+
k: "value"
|
|
32
|
+
}]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
maxLength: {
|
|
36
|
+
t: 0,
|
|
37
|
+
b: {
|
|
38
|
+
t: 2,
|
|
39
|
+
i: [
|
|
40
|
+
{
|
|
41
|
+
t: 3,
|
|
42
|
+
v: "The value exceeds "
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
t: 4,
|
|
46
|
+
k: "value"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
t: 3,
|
|
50
|
+
v: " characters"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
inputMax: {
|
|
56
|
+
t: 0,
|
|
57
|
+
b: {
|
|
58
|
+
t: 2,
|
|
59
|
+
i: [{
|
|
60
|
+
t: 3,
|
|
61
|
+
v: "Must be less than "
|
|
62
|
+
}, {
|
|
63
|
+
t: 4,
|
|
64
|
+
k: "value"
|
|
65
|
+
}]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
es: {
|
|
70
|
+
inputMin: {
|
|
71
|
+
t: 0,
|
|
72
|
+
b: {
|
|
73
|
+
t: 2,
|
|
74
|
+
i: [{
|
|
75
|
+
t: 3,
|
|
76
|
+
v: "Debe ser mayor a "
|
|
77
|
+
}, {
|
|
78
|
+
t: 4,
|
|
79
|
+
k: "value"
|
|
80
|
+
}]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
maxLength: {
|
|
84
|
+
t: 0,
|
|
85
|
+
b: {
|
|
86
|
+
t: 2,
|
|
87
|
+
i: [
|
|
88
|
+
{
|
|
89
|
+
t: 3,
|
|
90
|
+
v: "El valor excede los "
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
t: 4,
|
|
94
|
+
k: "value"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
t: 3,
|
|
98
|
+
v: " carácteres"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
inputMax: {
|
|
104
|
+
t: 0,
|
|
105
|
+
b: {
|
|
106
|
+
t: 2,
|
|
107
|
+
i: [{
|
|
108
|
+
t: 3,
|
|
109
|
+
v: "Debe ser menor a "
|
|
110
|
+
}, {
|
|
111
|
+
t: 4,
|
|
112
|
+
k: "value"
|
|
113
|
+
}]
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"Convert to uppercase": {
|
|
117
|
+
t: 0,
|
|
118
|
+
b: {
|
|
119
|
+
t: 2,
|
|
120
|
+
i: [{ t: 3 }],
|
|
121
|
+
s: "Convertir a mayúsculas"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
Remove: {
|
|
125
|
+
t: 0,
|
|
126
|
+
b: {
|
|
127
|
+
t: 2,
|
|
128
|
+
i: [{ t: 3 }],
|
|
129
|
+
s: "Eliminar"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region lib/components/inputs/VnInput.vue
|
|
138
|
+
var O = {
|
|
139
|
+
__name: "VnInput",
|
|
140
|
+
props: /*@__PURE__*/ d({
|
|
141
|
+
isOutlined: {
|
|
142
|
+
type: Boolean,
|
|
143
|
+
default: !1
|
|
144
|
+
},
|
|
145
|
+
info: {
|
|
146
|
+
type: String,
|
|
147
|
+
default: ""
|
|
148
|
+
},
|
|
149
|
+
clearable: {
|
|
150
|
+
type: Boolean,
|
|
151
|
+
default: !0
|
|
152
|
+
},
|
|
153
|
+
emptyToNull: {
|
|
154
|
+
type: Boolean,
|
|
155
|
+
default: !0
|
|
156
|
+
},
|
|
157
|
+
insertable: {
|
|
158
|
+
type: Boolean,
|
|
159
|
+
default: !1
|
|
160
|
+
},
|
|
161
|
+
maxlength: {
|
|
162
|
+
type: Number,
|
|
163
|
+
default: null
|
|
164
|
+
},
|
|
165
|
+
uppercase: {
|
|
166
|
+
type: Boolean,
|
|
167
|
+
default: !1
|
|
168
|
+
}
|
|
169
|
+
}, {
|
|
170
|
+
modelValue: { default: null },
|
|
171
|
+
modelModifiers: {}
|
|
172
|
+
}),
|
|
173
|
+
emits: /*@__PURE__*/ d(["remove"], ["update:modelValue"]),
|
|
174
|
+
setup(d, { expose: T, emit: E }) {
|
|
175
|
+
let D = x(), { isRequired: O, requiredFieldRule: k } = e(D), { t: A } = w(), j = E, M = d, N = S(d, "modelValue"), P = [
|
|
176
|
+
"number",
|
|
177
|
+
"search",
|
|
178
|
+
"tel",
|
|
179
|
+
"url",
|
|
180
|
+
"password"
|
|
181
|
+
], F = (e) => {
|
|
182
|
+
let t = e;
|
|
183
|
+
M.emptyToNull && t === "" && (t = null), N.value = t;
|
|
184
|
+
}, I = _(null), L = _(!1), R = i(() => M.isOutlined ? {
|
|
185
|
+
dense: !0,
|
|
186
|
+
outlined: !0,
|
|
187
|
+
rounded: !0
|
|
188
|
+
} : {}), z = (e) => {
|
|
189
|
+
I.value?.focus(e);
|
|
190
|
+
}, B = (e) => {
|
|
191
|
+
p(() => {
|
|
192
|
+
let t = e.target || I.value?.$el?.querySelector("input"), n = e.target.type || t?.getAttribute("type");
|
|
193
|
+
if (n !== "email") {
|
|
194
|
+
if (!P.includes(n)) {
|
|
195
|
+
if (t?.setSelectionRange) {
|
|
196
|
+
let e = t.value?.length ?? 0;
|
|
197
|
+
t.setSelectionRange(e, e);
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
t?.select?.();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
T({
|
|
206
|
+
focus: z,
|
|
207
|
+
vnInputRef: I
|
|
208
|
+
});
|
|
209
|
+
let V = i(() => [
|
|
210
|
+
k,
|
|
211
|
+
...D.rules ?? [],
|
|
212
|
+
(e) => {
|
|
213
|
+
let t = M.maxlength;
|
|
214
|
+
if (t && +e?.length > t) return A("maxLength", { value: t });
|
|
215
|
+
let { min: n, max: r } = D, i = n === void 0 ? void 0 : Number(n), a = r === void 0 ? void 0 : Number(r);
|
|
216
|
+
return i !== void 0 && i >= 0 && Math.floor(e) < i ? A("inputMin", { value: i }) : a !== void 0 && a > 0 && Math.floor(e) > a ? A("inputMax", { value: a }) : !0;
|
|
217
|
+
}
|
|
218
|
+
]), H = (e) => {
|
|
219
|
+
e.key !== "Backspace" && M.insertable && e.key.match(/[0-9]/) && U(e);
|
|
220
|
+
}, U = (e) => {
|
|
221
|
+
e.preventDefault();
|
|
222
|
+
let t = e.target, n = t.selectionStart, r = M.maxlength, i = N.value;
|
|
223
|
+
i ||= e.key;
|
|
224
|
+
let a = e.key;
|
|
225
|
+
a && !isNaN(a) && n < r && F(i.substring(0, n) + a + i.substring(n + 1)), p(() => {
|
|
226
|
+
t.setSelectionRange(n + 1, n + 1);
|
|
227
|
+
});
|
|
228
|
+
}, W = () => {
|
|
229
|
+
N.value = N.value?.toUpperCase() || "";
|
|
230
|
+
};
|
|
231
|
+
return h(() => {
|
|
232
|
+
D.autofocus && z();
|
|
233
|
+
}), (e, i) => {
|
|
234
|
+
let p = r, h = t, _ = n;
|
|
235
|
+
return g(), s("div", {
|
|
236
|
+
onMouseover: i[1] ||= (e) => L.value = !0,
|
|
237
|
+
onMouseleave: i[2] ||= (e) => L.value = !1
|
|
238
|
+
}, [u(_, f({
|
|
239
|
+
ref_key: "vnInputRef",
|
|
240
|
+
ref: I,
|
|
241
|
+
"model-value": b(N),
|
|
242
|
+
"onUpdate:modelValue": F
|
|
243
|
+
}, {
|
|
244
|
+
...b(D),
|
|
245
|
+
...R.value
|
|
246
|
+
}, {
|
|
247
|
+
class: { required: b(O) },
|
|
248
|
+
onKeydown: H,
|
|
249
|
+
onFocus: B,
|
|
250
|
+
clearable: !1,
|
|
251
|
+
rules: V.value,
|
|
252
|
+
"lazy-rules": !0,
|
|
253
|
+
"hide-bottom-space": "",
|
|
254
|
+
"data-cy": (b(D)["data-cy"] ?? b(D).label) + "_input"
|
|
255
|
+
}), c({
|
|
256
|
+
append: C(() => [
|
|
257
|
+
u(h, {
|
|
258
|
+
name: "close",
|
|
259
|
+
size: "xs",
|
|
260
|
+
class: "cursor-pointer",
|
|
261
|
+
style: m({ visibility: L.value && b(N) && !b(D).disabled && !b(D).readonly && M.clearable ? "visible" : "hidden" }),
|
|
262
|
+
onClick: i[0] ||= () => {
|
|
263
|
+
F(null), I.value?.focus(), j("remove");
|
|
264
|
+
}
|
|
265
|
+
}, {
|
|
266
|
+
default: C(() => [u(p, null, {
|
|
267
|
+
default: C(() => [l(y(b(A)("Remove")), 1)]),
|
|
268
|
+
_: 1
|
|
269
|
+
})]),
|
|
270
|
+
_: 1
|
|
271
|
+
}, 8, ["style"]),
|
|
272
|
+
!b(D).disabled && !b(D).readonly && M.uppercase ? (g(), a(h, {
|
|
273
|
+
key: 0,
|
|
274
|
+
name: "match_case",
|
|
275
|
+
size: "xs",
|
|
276
|
+
onClick: W,
|
|
277
|
+
class: "uppercase-icon"
|
|
278
|
+
}, {
|
|
279
|
+
default: C(() => [u(p, null, {
|
|
280
|
+
default: C(() => [l(y(b(A)("Convert to uppercase")), 1)]),
|
|
281
|
+
_: 1
|
|
282
|
+
})]),
|
|
283
|
+
_: 1
|
|
284
|
+
})) : o("", !0),
|
|
285
|
+
e.$slots.append && !b(D).disabled ? v(e.$slots, "append", {}, void 0, void 0, 1) : o("", !0),
|
|
286
|
+
d.info ? (g(), a(h, {
|
|
287
|
+
key: 2,
|
|
288
|
+
name: "info"
|
|
289
|
+
}, {
|
|
290
|
+
default: C(() => [u(p, { "max-width": "350px" }, {
|
|
291
|
+
default: C(() => [l(y(d.info), 1)]),
|
|
292
|
+
_: 1
|
|
293
|
+
})]),
|
|
294
|
+
_: 1
|
|
295
|
+
})) : o("", !0)
|
|
296
|
+
]),
|
|
297
|
+
_: 2
|
|
298
|
+
}, [e.$slots.prepend ? {
|
|
299
|
+
name: "prepend",
|
|
300
|
+
fn: C(() => [v(e.$slots, "prepend")]),
|
|
301
|
+
key: "0"
|
|
302
|
+
} : void 0]), 1040, [
|
|
303
|
+
"model-value",
|
|
304
|
+
"class",
|
|
305
|
+
"rules",
|
|
306
|
+
"data-cy"
|
|
307
|
+
])], 32);
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
typeof D == "function" && D(O);
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region lib/components/index.js
|
|
314
|
+
var k = /* @__PURE__ */ E({ VnInput: () => O });
|
|
315
|
+
//#endregion
|
|
316
|
+
export { O as n, k as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./components-C4qIWgU6.cjs");exports.VnInput=e.n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useRequired-I81Vonhu.cjs");exports.useRequired=e.t,exports.useValidator=e.n;
|
package/dist/stores.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useValidationsStore-CmGCLBNO.cjs");exports.useValidationsStore=e.t;
|
package/dist/stores.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { t as e } from "./useValidationsStore-B5R8zW5O.js";
|
|
2
|
+
import { useI18n as t } from "vue-i18n";
|
|
3
|
+
import n from "validator";
|
|
4
|
+
//#region lib/composables/useValidator.js
|
|
5
|
+
function r() {
|
|
6
|
+
let r = e().validations;
|
|
7
|
+
function i(e) {
|
|
8
|
+
let t = r;
|
|
9
|
+
if (!t || !e) return;
|
|
10
|
+
let n = e.split("."), i = n[0], a = n[1], s = i.charAt(0).toUpperCase() + i.slice(1);
|
|
11
|
+
if (!t[s]) return;
|
|
12
|
+
let c = t[s].validations;
|
|
13
|
+
if (c[a]) return c[a].map((e) => o(e)[e.validation]);
|
|
14
|
+
}
|
|
15
|
+
let { t: a } = t({ useScope: "global" }), o = function(e = {}) {
|
|
16
|
+
return {
|
|
17
|
+
format: (t) => {
|
|
18
|
+
let { allowNull: n, with: r, allowBlank: i } = e, o = a(e.message) || e.message;
|
|
19
|
+
if (!i && t === "" || !n && t === null || !new RegExp(r).test(t)) return o;
|
|
20
|
+
},
|
|
21
|
+
presence: (t) => {
|
|
22
|
+
let r = a("globals.valueCantBeEmpty");
|
|
23
|
+
return e.message && (r = a(e.message) || e.message), !n.isEmpty(t ? String(t) : "") || r;
|
|
24
|
+
},
|
|
25
|
+
required: (e, t) => e ? t === 0 || !!t || a("globals.fieldRequired") : null,
|
|
26
|
+
length: (t) => {
|
|
27
|
+
let r = {
|
|
28
|
+
min: e.min || e.is,
|
|
29
|
+
max: e.max || e.is
|
|
30
|
+
};
|
|
31
|
+
t = String(t), t ||= "";
|
|
32
|
+
let i = `Value should have at most ${r.max} characters`;
|
|
33
|
+
return e.is && (i = `Value should be ${e.is} characters long`), e.min && (i = `Value should have at least ${e.min} characters`), e.min && e.max && (i = `Value should have a length between ${e.min} and ${e.max}`), n.isLength(t, r) || i;
|
|
34
|
+
},
|
|
35
|
+
numericality: (t) => e.int ? n.isInt(t) || "Value should be integer" : n.isNumeric(t) || "Value should be a number",
|
|
36
|
+
min: (e, t) => {
|
|
37
|
+
if (t >= 0 && Math.floor(e) < t) return a("inputMin", { value: t });
|
|
38
|
+
},
|
|
39
|
+
custom: (t) => Function(`return (${e.bindedFunction})`)()(t) || "Invalid value"
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
validate: i,
|
|
44
|
+
validations: o,
|
|
45
|
+
models: r
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region lib/composables/useRequired.js
|
|
50
|
+
function i(e) {
|
|
51
|
+
let { validations: t } = r(), n = typeof e.required == "boolean" ? e.required : Object.keys(e).includes("required");
|
|
52
|
+
return {
|
|
53
|
+
isRequired: n,
|
|
54
|
+
requiredFieldRule: (e) => t().required(n, e)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { r as n, i as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const l=require("./useValidationsStore-CmGCLBNO.cjs");let u=require("vue-i18n"),d=require("validator");d=c(d,1);function f(){let e=l.t().validations;function t(t){let n=e;if(!n||!t)return;let i=t.split(`.`),a=i[0],o=i[1],s=a.charAt(0).toUpperCase()+a.slice(1);if(!n[s])return;let c=n[s].validations;if(c[o])return c[o].map(e=>r(e)[e.validation])}let{t:n}=(0,u.useI18n)({useScope:`global`}),r=function(e={}){return{format:t=>{let{allowNull:r,with:i,allowBlank:a}=e,o=n(e.message)||e.message;if(!a&&t===``||!r&&t===null||!new RegExp(i).test(t))return o},presence:t=>{let r=n(`globals.valueCantBeEmpty`);return e.message&&(r=n(e.message)||e.message),!d.default.isEmpty(t?String(t):``)||r},required:(e,t)=>e?t===0||!!t||n(`globals.fieldRequired`):null,length:t=>{let n={min:e.min||e.is,max:e.max||e.is};t=String(t),t||=``;let r=`Value should have at most ${n.max} characters`;return e.is&&(r=`Value should be ${e.is} characters long`),e.min&&(r=`Value should have at least ${e.min} characters`),e.min&&e.max&&(r=`Value should have a length between ${e.min} and ${e.max}`),d.default.isLength(t,n)||r},numericality:t=>e.int?d.default.isInt(t)||`Value should be integer`:d.default.isNumeric(t)||`Value should be a number`,min:(e,t)=>{if(t>=0&&Math.floor(e)<t)return n(`inputMin`,{value:t})},custom:t=>Function(`return (${e.bindedFunction})`)()(t)||`Invalid value`}};return{validate:t,validations:r,models:e}}function p(e){let{validations:t}=f(),n=typeof e.required==`boolean`?e.required:Object.keys(e).includes(`required`);return{isRequired:n,requiredFieldRule:e=>t().required(n,e)}}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return p}});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineStore as e } from "pinia";
|
|
2
|
+
//#region lib/config.js
|
|
3
|
+
var t = {}, n = ["axios"], r;
|
|
4
|
+
function i(e = {}) {
|
|
5
|
+
let i = n.filter((t) => !e[t]);
|
|
6
|
+
if (i.length) throw Error(`vn-front-lib: missing required configuration: ${i.join(", ")}. Pass app.use(VnFrontLib, { ${i.join(", ")} })`);
|
|
7
|
+
Object.assign(t, e), r = t.axios;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region lib/stores/useValidationsStore.js
|
|
11
|
+
var a = e("validationsStore", {
|
|
12
|
+
state: () => ({ validations: null }),
|
|
13
|
+
actions: { async fetchModels() {
|
|
14
|
+
let { data: e } = await r.get("Schemas/modelinfo");
|
|
15
|
+
this.validations = e;
|
|
16
|
+
} }
|
|
17
|
+
});
|
|
18
|
+
//#endregion
|
|
19
|
+
export { r as n, i as r, a as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require("pinia");var t={},n=[`axios`],r;function i(e={}){let i=n.filter(t=>!e[t]);if(i.length)throw Error(`vn-front-lib: missing required configuration: ${i.join(`, `)}. Pass app.use(VnFrontLib, { ${i.join(`, `)} })`);Object.assign(t,e),r=t.axios}var a=(0,e.defineStore)(`validationsStore`,{state:()=>({validations:null}),actions:{async fetchModels(){let{data:e}=await r.get(`Schemas/modelinfo`);this.validations=e}}});Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return a}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./useRequired-I81Vonhu.cjs"),t=require("./useValidationsStore-CmGCLBNO.cjs"),n=require("./components-C4qIWgU6.cjs");require("./composables.cjs");function r(e,r={}){t.r(r);for(let t in n.t)e.component(t,n.t[t])}var i={install:r};exports.VnInput=n.n,Object.defineProperty(exports,"axios",{enumerable:!0,get:function(){return t.n}}),exports.default=i,exports.setConfig=t.r,exports.useRequired=e.t,exports.useValidator=e.n;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { n as e, t } from "./components-Ct0VDaxz.js";
|
|
2
|
+
import { n, r } from "./useValidationsStore-B5R8zW5O.js";
|
|
3
|
+
import { n as i, t as a } from "./useRequired-BDeZirAF.js";
|
|
4
|
+
import "./composables.js";
|
|
5
|
+
//#region lib/main.js
|
|
6
|
+
function o(e, n = {}) {
|
|
7
|
+
r(n);
|
|
8
|
+
for (let n in t) e.component(n, t[n]);
|
|
9
|
+
}
|
|
10
|
+
var s = { install: o };
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as VnInput, n as axios, s as default, r as setConfig, a as useRequired, i as useValidator };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as VnInput } from './inputs/VnInput.vue';
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, useAttrs, nextTick, onMounted } from 'vue';
|
|
3
|
+
import { useI18n } from 'vue-i18n';
|
|
4
|
+
import { useRequired } from 'lib/composables/useRequired';
|
|
5
|
+
|
|
6
|
+
const $attrs = useAttrs();
|
|
7
|
+
const { isRequired, requiredFieldRule } = useRequired($attrs);
|
|
8
|
+
const { t } = useI18n();
|
|
9
|
+
const emit = defineEmits(['remove']);
|
|
10
|
+
|
|
11
|
+
const $props = defineProps({
|
|
12
|
+
isOutlined: { type: Boolean, default: false },
|
|
13
|
+
info: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: '',
|
|
16
|
+
},
|
|
17
|
+
clearable: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: true,
|
|
20
|
+
},
|
|
21
|
+
emptyToNull: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: true,
|
|
24
|
+
},
|
|
25
|
+
insertable: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
maxlength: {
|
|
30
|
+
type: Number,
|
|
31
|
+
default: null,
|
|
32
|
+
},
|
|
33
|
+
uppercase: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const model = defineModel({ default: null });
|
|
40
|
+
const value = model;
|
|
41
|
+
const selectableTypes = ['number', 'search', 'tel', 'url', 'password'];
|
|
42
|
+
|
|
43
|
+
const update = (val) => {
|
|
44
|
+
let next = val;
|
|
45
|
+
if ($props.emptyToNull && next === '') next = null;
|
|
46
|
+
value.value = next;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const vnInputRef = ref(null);
|
|
50
|
+
|
|
51
|
+
const hover = ref(false);
|
|
52
|
+
const styleAttrs = computed(() => {
|
|
53
|
+
return $props.isOutlined
|
|
54
|
+
? {
|
|
55
|
+
dense: true,
|
|
56
|
+
outlined: true,
|
|
57
|
+
rounded: true,
|
|
58
|
+
}
|
|
59
|
+
: {};
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const focus = (evt) => {
|
|
63
|
+
vnInputRef.value?.focus(evt);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const onFocus = (evt) => {
|
|
67
|
+
nextTick(() => {
|
|
68
|
+
const inputEl = evt.target || vnInputRef.value?.$el?.querySelector('input');
|
|
69
|
+
const realType = evt.target.type || inputEl?.getAttribute('type');
|
|
70
|
+
if (realType === 'email') {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (!selectableTypes.includes(realType)) {
|
|
74
|
+
if (inputEl?.setSelectionRange) {
|
|
75
|
+
const end = inputEl.value?.length ?? 0;
|
|
76
|
+
inputEl.setSelectionRange(end, end);
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
inputEl?.select?.();
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
defineExpose({
|
|
85
|
+
focus,
|
|
86
|
+
vnInputRef,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const mixinRules = computed(() => {
|
|
90
|
+
return [
|
|
91
|
+
requiredFieldRule,
|
|
92
|
+
...($attrs.rules ?? []),
|
|
93
|
+
(val) => {
|
|
94
|
+
const maxlength = $props.maxlength;
|
|
95
|
+
if (maxlength && +val?.length > maxlength)
|
|
96
|
+
return t('maxLength', { value: maxlength });
|
|
97
|
+
const { min, max } = $attrs;
|
|
98
|
+
const minNum = min !== undefined ? Number(min) : undefined;
|
|
99
|
+
const maxNum = max !== undefined ? Number(max) : undefined;
|
|
100
|
+
|
|
101
|
+
if (minNum !== undefined && minNum >= 0 && Math.floor(val) < minNum)
|
|
102
|
+
return t('inputMin', { value: minNum });
|
|
103
|
+
|
|
104
|
+
if (maxNum !== undefined && maxNum > 0 && Math.floor(val) > maxNum)
|
|
105
|
+
return t('inputMax', { value: maxNum });
|
|
106
|
+
|
|
107
|
+
return true;
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const handleKeydown = (e) => {
|
|
113
|
+
if (e.key === 'Backspace') return;
|
|
114
|
+
|
|
115
|
+
if ($props.insertable && e.key.match(/[0-9]/)) {
|
|
116
|
+
handleInsertMode(e);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const handleInsertMode = (e) => {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
const input = e.target;
|
|
123
|
+
const cursorPos = input.selectionStart;
|
|
124
|
+
const maxlength = $props.maxlength;
|
|
125
|
+
let currentValue = value.value;
|
|
126
|
+
if (!currentValue) currentValue = e.key;
|
|
127
|
+
const newValue = e.key;
|
|
128
|
+
if (newValue && !isNaN(newValue) && cursorPos < maxlength) {
|
|
129
|
+
update(
|
|
130
|
+
currentValue.substring(0, cursorPos) +
|
|
131
|
+
newValue +
|
|
132
|
+
currentValue.substring(cursorPos + 1),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
nextTick(() => {
|
|
137
|
+
input.setSelectionRange(cursorPos + 1, cursorPos + 1);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const handleUppercase = () => {
|
|
142
|
+
value.value = value.value?.toUpperCase() || '';
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
onMounted(() => {
|
|
146
|
+
if ($attrs.autofocus) focus();
|
|
147
|
+
});
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<template>
|
|
151
|
+
<div @mouseover="hover = true" @mouseleave="hover = false">
|
|
152
|
+
<QInput
|
|
153
|
+
ref="vnInputRef"
|
|
154
|
+
:model-value="value"
|
|
155
|
+
@update:model-value="update"
|
|
156
|
+
v-bind="{ ...$attrs, ...styleAttrs }"
|
|
157
|
+
:class="{ required: isRequired }"
|
|
158
|
+
@keydown="handleKeydown"
|
|
159
|
+
@focus="onFocus"
|
|
160
|
+
:clearable="false"
|
|
161
|
+
:rules="mixinRules"
|
|
162
|
+
:lazy-rules="true"
|
|
163
|
+
hide-bottom-space
|
|
164
|
+
:data-cy="($attrs['data-cy'] ?? $attrs.label) + '_input'"
|
|
165
|
+
>
|
|
166
|
+
<template #prepend v-if="$slots.prepend">
|
|
167
|
+
<slot name="prepend" />
|
|
168
|
+
</template>
|
|
169
|
+
<template #append>
|
|
170
|
+
<QIcon
|
|
171
|
+
name="close"
|
|
172
|
+
size="xs"
|
|
173
|
+
class="cursor-pointer"
|
|
174
|
+
:style="{
|
|
175
|
+
visibility:
|
|
176
|
+
hover &&
|
|
177
|
+
value &&
|
|
178
|
+
!$attrs.disabled &&
|
|
179
|
+
!$attrs.readonly &&
|
|
180
|
+
$props.clearable
|
|
181
|
+
? 'visible'
|
|
182
|
+
: 'hidden',
|
|
183
|
+
}"
|
|
184
|
+
@click="
|
|
185
|
+
() => {
|
|
186
|
+
update(null);
|
|
187
|
+
vnInputRef?.focus();
|
|
188
|
+
emit('remove');
|
|
189
|
+
}
|
|
190
|
+
"
|
|
191
|
+
>
|
|
192
|
+
<QTooltip>{{ t('Remove') }}</QTooltip>
|
|
193
|
+
</QIcon>
|
|
194
|
+
|
|
195
|
+
<QIcon
|
|
196
|
+
name="match_case"
|
|
197
|
+
size="xs"
|
|
198
|
+
v-if="!$attrs.disabled && !$attrs.readonly && $props.uppercase"
|
|
199
|
+
@click="handleUppercase"
|
|
200
|
+
class="uppercase-icon"
|
|
201
|
+
>
|
|
202
|
+
<QTooltip>
|
|
203
|
+
{{ t('Convert to uppercase') }}
|
|
204
|
+
</QTooltip>
|
|
205
|
+
</QIcon>
|
|
206
|
+
|
|
207
|
+
<slot name="append" v-if="$slots.append && !$attrs.disabled" />
|
|
208
|
+
<QIcon v-if="info" name="info">
|
|
209
|
+
<QTooltip max-width="350px">
|
|
210
|
+
{{ info }}
|
|
211
|
+
</QTooltip>
|
|
212
|
+
</QIcon>
|
|
213
|
+
</template>
|
|
214
|
+
</QInput>
|
|
215
|
+
</div>
|
|
216
|
+
</template>
|
|
217
|
+
|
|
218
|
+
<style>
|
|
219
|
+
.uppercase-icon {
|
|
220
|
+
transition:
|
|
221
|
+
color 0.3s,
|
|
222
|
+
transform 0.2s;
|
|
223
|
+
cursor: pointer;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.uppercase-icon:hover {
|
|
227
|
+
color: #ed9937;
|
|
228
|
+
transform: scale(1.2);
|
|
229
|
+
}
|
|
230
|
+
</style>
|
|
231
|
+
<i18n lang="yaml">
|
|
232
|
+
en:
|
|
233
|
+
inputMin: Must be more than {value}
|
|
234
|
+
maxLength: The value exceeds {value} characters
|
|
235
|
+
inputMax: Must be less than {value}
|
|
236
|
+
|
|
237
|
+
es:
|
|
238
|
+
inputMin: Debe ser mayor a {value}
|
|
239
|
+
maxLength: El valor excede los {value} carácteres
|
|
240
|
+
inputMax: Debe ser menor a {value}
|
|
241
|
+
Convert to uppercase: Convertir a mayúsculas
|
|
242
|
+
Remove: Eliminar
|
|
243
|
+
</i18n>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useValidator } from 'lib/composables/useValidator';
|
|
2
|
+
|
|
3
|
+
export function useRequired($attrs) {
|
|
4
|
+
const { validations } = useValidator();
|
|
5
|
+
const isRequired =
|
|
6
|
+
typeof $attrs['required'] === 'boolean'
|
|
7
|
+
? $attrs['required']
|
|
8
|
+
: Object.keys($attrs).includes('required');
|
|
9
|
+
const requiredFieldRule = (val) => validations().required(isRequired, val);
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
isRequired,
|
|
13
|
+
requiredFieldRule,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useI18n } from 'vue-i18n';
|
|
2
|
+
import validator from 'validator';
|
|
3
|
+
import { useValidationsStore } from 'lib/stores/useValidationsStore';
|
|
4
|
+
|
|
5
|
+
export function useValidator() {
|
|
6
|
+
const models = useValidationsStore().validations;
|
|
7
|
+
|
|
8
|
+
function validate(propertyRule) {
|
|
9
|
+
const modelInfo = models;
|
|
10
|
+
if (!modelInfo || !propertyRule) return;
|
|
11
|
+
|
|
12
|
+
const rule = propertyRule.split('.');
|
|
13
|
+
const model = rule[0];
|
|
14
|
+
const property = rule[1];
|
|
15
|
+
const modelName = model.charAt(0).toUpperCase() + model.slice(1);
|
|
16
|
+
|
|
17
|
+
if (!modelInfo[modelName]) return;
|
|
18
|
+
|
|
19
|
+
const modelValidations = modelInfo[modelName].validations;
|
|
20
|
+
|
|
21
|
+
if (!modelValidations[property]) return;
|
|
22
|
+
|
|
23
|
+
const rules = modelValidations[property].map((validation) => {
|
|
24
|
+
return validations(validation)[validation.validation];
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return rules;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { t } = useI18n({ useScope: 'global' });
|
|
31
|
+
const validations = function (validation = {}) {
|
|
32
|
+
return {
|
|
33
|
+
format: (value) => {
|
|
34
|
+
const { allowNull, with: format, allowBlank } = validation;
|
|
35
|
+
const message = t(validation.message) || validation.message;
|
|
36
|
+
if (!allowBlank && value === '') return message;
|
|
37
|
+
if (!allowNull && value === null) return message;
|
|
38
|
+
|
|
39
|
+
const isValid = new RegExp(format).test(value);
|
|
40
|
+
if (!isValid) return message;
|
|
41
|
+
},
|
|
42
|
+
presence: (value) => {
|
|
43
|
+
let message = t(`globals.valueCantBeEmpty`);
|
|
44
|
+
if (validation.message)
|
|
45
|
+
message = t(validation.message) || validation.message;
|
|
46
|
+
|
|
47
|
+
return !validator.isEmpty(value ? String(value) : '') || message;
|
|
48
|
+
},
|
|
49
|
+
required: (required, value) => {
|
|
50
|
+
return required
|
|
51
|
+
? value === 0 || !!value || t('globals.fieldRequired')
|
|
52
|
+
: null;
|
|
53
|
+
},
|
|
54
|
+
length: (value) => {
|
|
55
|
+
const options = {
|
|
56
|
+
min: validation.min || validation.is,
|
|
57
|
+
max: validation.max || validation.is,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
value = String(value);
|
|
61
|
+
|
|
62
|
+
if (!value) value = '';
|
|
63
|
+
|
|
64
|
+
let message = `Value should have at most ${options.max} characters`;
|
|
65
|
+
if (validation.is)
|
|
66
|
+
message = `Value should be ${validation.is} characters long`;
|
|
67
|
+
if (validation.min)
|
|
68
|
+
message = `Value should have at least ${validation.min} characters`;
|
|
69
|
+
if (validation.min && validation.max)
|
|
70
|
+
message = `Value should have a length between ${validation.min} and ${validation.max}`;
|
|
71
|
+
|
|
72
|
+
return validator.isLength(value, options) || message;
|
|
73
|
+
},
|
|
74
|
+
numericality: (value) => {
|
|
75
|
+
if (validation.int)
|
|
76
|
+
return validator.isInt(value) || 'Value should be integer';
|
|
77
|
+
return validator.isNumeric(value) || 'Value should be a number';
|
|
78
|
+
},
|
|
79
|
+
min: (value, min) => {
|
|
80
|
+
if (min >= 0)
|
|
81
|
+
if (Math.floor(value) < min) return t('inputMin', { value: min });
|
|
82
|
+
},
|
|
83
|
+
custom: (value) =>
|
|
84
|
+
new Function(`return (${validation.bindedFunction})`)()(value) ||
|
|
85
|
+
'Invalid value',
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
validate,
|
|
91
|
+
validations,
|
|
92
|
+
models,
|
|
93
|
+
};
|
|
94
|
+
}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Default library configuration, overridden by whatever is passed to app.use(VnFrontLib, options)
|
|
2
|
+
const config = {};
|
|
3
|
+
const requiredOptions = ['axios'];
|
|
4
|
+
export default config;
|
|
5
|
+
export let axios;
|
|
6
|
+
|
|
7
|
+
export function setConfig(options = {}) {
|
|
8
|
+
const missing = requiredOptions.filter((key) => !options[key]);
|
|
9
|
+
if (missing.length) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`vn-front-lib: missing required configuration: ${missing.join(', ')}. Pass app.use(VnFrontLib, { ${missing.join(', ')} })`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
Object.assign(config, options);
|
|
15
|
+
axios = config.axios;
|
|
16
|
+
}
|
package/lib/main.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './components';
|
|
2
|
+
export * from './composables';
|
|
3
|
+
export * from './config';
|
|
4
|
+
import * as components from './components';
|
|
5
|
+
import { setConfig } from './config';
|
|
6
|
+
|
|
7
|
+
function install(app, options = {}) {
|
|
8
|
+
setConfig(options);
|
|
9
|
+
for (const name in components) {
|
|
10
|
+
app.component(name, components[name]);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
install,
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useValidationsStore';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { axios } from 'lib/config';
|
|
3
|
+
|
|
4
|
+
export const useValidationsStore = defineStore('validationsStore', {
|
|
5
|
+
state: () => ({
|
|
6
|
+
validations: null,
|
|
7
|
+
}),
|
|
8
|
+
actions: {
|
|
9
|
+
async fetchModels() {
|
|
10
|
+
const { data } = await axios.get('Schemas/modelinfo');
|
|
11
|
+
this.validations = data;
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@verdnatura/vn-front-lib",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist",
|
|
6
|
+
"lib"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/vn-front-lib.cjs",
|
|
10
|
+
"module": "./dist/vn-front-lib.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"vnSource": "./lib/main.js",
|
|
14
|
+
"import": "./dist/vn-front-lib.js",
|
|
15
|
+
"require": "./dist/vn-front-lib.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./components": {
|
|
18
|
+
"vnSource": "./lib/components/index.js",
|
|
19
|
+
"import": "./dist/components.js",
|
|
20
|
+
"require": "./dist/components.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./composables": {
|
|
23
|
+
"vnSource": "./lib/composables/index.js",
|
|
24
|
+
"import": "./dist/composables.js",
|
|
25
|
+
"require": "./dist/composables.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./stores": {
|
|
28
|
+
"vnSource": "./lib/stores/index.js",
|
|
29
|
+
"import": "./dist/stores.js",
|
|
30
|
+
"require": "./dist/stores.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./style.css": "./dist/vn-front-lib.css"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"dev": "vite",
|
|
36
|
+
"build": "vite build",
|
|
37
|
+
"lint": "oxlint",
|
|
38
|
+
"lint:fix": "oxlint --fix",
|
|
39
|
+
"fmt": "oxfmt",
|
|
40
|
+
"fmt:check": "oxfmt --check"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@intlify/unplugin-vue-i18n": "^11.2.4",
|
|
44
|
+
"@quasar/vite-plugin": "^1.12.0",
|
|
45
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
46
|
+
"@vue/test-utils": "^2.4.11",
|
|
47
|
+
"axios": "^1.18.1",
|
|
48
|
+
"jsdom": "^30.0.1",
|
|
49
|
+
"oxfmt": "^0.61.0",
|
|
50
|
+
"oxlint": "^1.76.0",
|
|
51
|
+
"pinia": "^2.3.1",
|
|
52
|
+
"unplugin-vue-components": "^32.1.0",
|
|
53
|
+
"validator": "^13.15.35",
|
|
54
|
+
"vite": "^8.1.1",
|
|
55
|
+
"vitest": "^4.1.10",
|
|
56
|
+
"vue": "^3.5.13",
|
|
57
|
+
"vue-i18n": "^9.14.4",
|
|
58
|
+
"yaml": "^2.9.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"axios": ">=1.0.0",
|
|
62
|
+
"pinia": ">=2.0.0",
|
|
63
|
+
"quasar": ">=2.0.0",
|
|
64
|
+
"validator": ">=13.0.0",
|
|
65
|
+
"vue": ">=3.5.0",
|
|
66
|
+
"vue-i18n": ">=9.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|