@nexdom/uimed-vue 1.2.0-beta.2 → 1.2.0-beta.3
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/AGENTS.md +1 -1
- package/CLAUDE.md +1 -0
- package/README.md +13 -0
- package/dist/components.d.ts +51 -2
- package/dist/components.js +312 -182
- package/dist/unit-test.js +1 -1
- package/package.json +4 -2
package/AGENTS.md
CHANGED
|
@@ -93,7 +93,7 @@ vp install # install dependencies
|
|
|
93
93
|
## Commands
|
|
94
94
|
|
|
95
95
|
- `vpr check` — lint, formatter, and type-check (requires `build`/`pack` to have run first for the type-check step)
|
|
96
|
-
- `vp test --coverage` — unit tests (Vitest, jsdom, 100% coverage threshold enforced)
|
|
96
|
+
- `vp test --coverage` — unit tests with coverage (Vitest, jsdom, 100% coverage threshold enforced)
|
|
97
97
|
- `vpr test:mutations` — mutation tests (Stryker; thresholds: high 100, low 95, break 95)
|
|
98
98
|
- `vpr test:e2e` — E2E tests (Playwright, runs against the built docs preview site)
|
|
99
99
|
- `vpr depcruise` — architecture/dependency rules (dependency-cruiser)
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/README.md
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
[](https://github.com/nexdom-healthtech/uimed-vue/actions/workflows/cd.yml)
|
|
5
5
|
[](https://github.com/nexdom-healthtech/uimed-vue/actions/workflows/dependabot/dependabot-updates)
|
|
6
6
|
|
|
7
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
8
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
9
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
10
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
11
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
12
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
13
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
14
|
+
[](https://sonar-qube-public.services-dev.nexdom.tec.br/dashboard?id=UIMed-Vue)
|
|
15
|
+
|
|
16
|
+
[](https://nexdom-healthtech.github.io/uimed-vue)
|
|
17
|
+
|
|
18
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
19
|
+
|
|
7
20
|
A ui framework for NEXDOM applications, based on [Material Design](https://m3.material.io/).
|
|
8
21
|
|
|
9
22
|
For more examples and information, check the [docs page](https://nexdom-healthtech.github.io/uimed-vue/).
|
package/dist/components.d.ts
CHANGED
|
@@ -92,6 +92,47 @@ interface Option {
|
|
|
92
92
|
action?: () => void;
|
|
93
93
|
}
|
|
94
94
|
//#endregion
|
|
95
|
+
//#region src/components/navigation-menu/types.d.ts
|
|
96
|
+
/**
|
|
97
|
+
* Props exposed by the {@link NavigationMenu} component.
|
|
98
|
+
*/
|
|
99
|
+
type NavigationMenuProps = {
|
|
100
|
+
/**
|
|
101
|
+
* Component id to use on automated tests.
|
|
102
|
+
*/
|
|
103
|
+
dataTestid?: string;
|
|
104
|
+
/**
|
|
105
|
+
* List of items to show in the {@link NavigationMenu}.
|
|
106
|
+
* Can be plain items, grouped or both.
|
|
107
|
+
*/
|
|
108
|
+
items?: Array<NavigationMenuParentItemOrItem>;
|
|
109
|
+
};
|
|
110
|
+
type NavigationMenuParentItemOrItem = NavigationMenuParentItem | NavigationMenuItem;
|
|
111
|
+
type NavigationMenuParentItem = {
|
|
112
|
+
/**
|
|
113
|
+
* Text to present for the group.
|
|
114
|
+
*/
|
|
115
|
+
description: string;
|
|
116
|
+
/**
|
|
117
|
+
* Child {@link NavigationMenuItem} list.
|
|
118
|
+
*/
|
|
119
|
+
items: Array<NavigationMenuItem>;
|
|
120
|
+
};
|
|
121
|
+
interface NavigationMenuItem {
|
|
122
|
+
/**
|
|
123
|
+
* Text to present for the item.
|
|
124
|
+
*/
|
|
125
|
+
description: string;
|
|
126
|
+
/**
|
|
127
|
+
* Route to navigate when item is clicked.
|
|
128
|
+
*/
|
|
129
|
+
route?: RouteLocationRaw;
|
|
130
|
+
/**
|
|
131
|
+
* Callback to be triggered when the item is clicked.
|
|
132
|
+
*/
|
|
133
|
+
action?: () => void;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
95
136
|
//#region src/components/root/types.d.ts
|
|
96
137
|
/**
|
|
97
138
|
* Props exposed by the {@link Root} component.
|
|
@@ -105,6 +146,10 @@ type RootProps = {
|
|
|
105
146
|
* App bar properties.
|
|
106
147
|
*/
|
|
107
148
|
appBar?: AppBarProps;
|
|
149
|
+
/**
|
|
150
|
+
* Navigation menu properties.
|
|
151
|
+
*/
|
|
152
|
+
navigationMenu?: NavigationMenuProps;
|
|
108
153
|
};
|
|
109
154
|
//#endregion
|
|
110
155
|
//#region src/components/root/root.vue.d.ts
|
|
@@ -293,7 +338,11 @@ declare const __VLS_export$4: import("vue", { with: { "resolution-mode": "import
|
|
|
293
338
|
modelValue?: string;
|
|
294
339
|
}> & Readonly<{
|
|
295
340
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
296
|
-
}>, {
|
|
341
|
+
}>, {
|
|
342
|
+
type: TextFieldType;
|
|
343
|
+
variant: TextFieldVariant;
|
|
344
|
+
clearable: boolean;
|
|
345
|
+
}, {}, {}, {}, string, import("vue", { with: { "resolution-mode": "import" } }).ComponentProvideOptions, false, {}, any>;
|
|
297
346
|
//#endregion
|
|
298
347
|
//#region src/components/grid/container/types.d.ts
|
|
299
348
|
/**
|
|
@@ -457,4 +506,4 @@ type __VLS_WithSlots<T, S> = T & {
|
|
|
457
506
|
};
|
|
458
507
|
};
|
|
459
508
|
//#endregion
|
|
460
|
-
export { type AppBarProps as AppBarConfig, type AppBarUserProps as AppBarUserConfig, _default as Btn, _default$1 as Column, _default$2 as Container, _default$3 as Frm, _default$4 as Root, _default$5 as Row, _default$6 as TextField };
|
|
509
|
+
export { type AppBarProps as AppBarConfig, type AppBarUserProps as AppBarUserConfig, _default as Btn, _default$1 as Column, _default$2 as Container, _default$3 as Frm, type NavigationMenuProps as NavigationMenuConfig, _default$4 as Root, _default$5 as Row, _default$6 as TextField };
|
package/dist/components.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as useVuetifyColor, t as messages } from "./use-toast-CACuYhK_.js";
|
|
2
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode,
|
|
3
|
-
import { VApp, VAppBar, VAvatar, VBadge, VBtn, VCard, VCardText, VCol, VContainer, VDivider, VForm, VIcon, VIconBtn, VList, VListGroup, VListItem, VListItemAction, VListSubheader, VMain, VMenu, VRow, VSnackbarQueue, VTextField } from "vuetify/components";
|
|
2
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, isRef, mergeModels, mergeProps, openBlock, ref, renderList, renderSlot, toDisplayString, toValue, unref, useModel, withCtx, withModifiers } from "vue";
|
|
3
|
+
import { VApp, VAppBar, VAppBarNavIcon, VAvatar, VBadge, VBtn, VCard, VCardText, VCol, VContainer, VDivider, VForm, VIcon, VIconBtn, VList, VListGroup, VListItem, VListItemAction, VListSubheader, VMain, VMenu, VNavigationDrawer, VRow, VSnackbarQueue, VTextField } from "vuetify/components";
|
|
4
4
|
import { formatDateTime, isEmail, isEmpty, isPhone, isUrl, toPeriodInterval } from "@nexdom/shared/utils";
|
|
5
5
|
//#region src/composables/navigation/use-route-props.ts
|
|
6
6
|
function useRouteProps(route) {
|
|
@@ -15,7 +15,7 @@ function isExternalRoute(route) {
|
|
|
15
15
|
}
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/components/app-bar/app-bar.vue?vue&type=script&setup=true&lang.ts
|
|
18
|
-
const _hoisted_1 = { class: "opacity-60" };
|
|
18
|
+
const _hoisted_1$1 = { class: "opacity-60" };
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/components/app-bar/app-bar.vue
|
|
21
21
|
var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
@@ -41,20 +41,28 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
41
41
|
notifications: {
|
|
42
42
|
type: Array,
|
|
43
43
|
required: false
|
|
44
|
+
},
|
|
45
|
+
navigation: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
required: true
|
|
44
48
|
}
|
|
45
49
|
}, {
|
|
46
50
|
"notificationsOpen": {
|
|
47
51
|
type: Boolean,
|
|
48
52
|
default: false
|
|
49
53
|
},
|
|
50
|
-
"notificationsOpenModifiers": {}
|
|
54
|
+
"notificationsOpenModifiers": {},
|
|
55
|
+
"navigationOpen": { type: Boolean },
|
|
56
|
+
"navigationOpenModifiers": {}
|
|
51
57
|
}),
|
|
52
|
-
emits: ["update:notificationsOpen"],
|
|
58
|
+
emits: ["update:notificationsOpen", "update:navigationOpen"],
|
|
53
59
|
setup(__props) {
|
|
54
60
|
const props = __props;
|
|
55
61
|
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
62
|
+
const navigationOpen = useModel(__props, "navigationOpen");
|
|
56
63
|
const helpBtnDataTestid = computed(() => `${props.dataTestid}-help`);
|
|
57
64
|
const notificationsBtnDataTestid = computed(() => `${props.dataTestid}-notifications`);
|
|
65
|
+
const navigationBtnDataTestid = computed(() => `${props.dataTestid}-navigation`);
|
|
58
66
|
const notificationsMenuDataTestid = computed(() => `${props.dataTestid}-notifications-menu`);
|
|
59
67
|
const userBtnDataTestid = computed(() => `${props.dataTestid}-user`);
|
|
60
68
|
const userMenuDataTestid = computed(() => `${props.dataTestid}-user-menu`);
|
|
@@ -90,6 +98,11 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
90
98
|
title: props.title,
|
|
91
99
|
"data-testid": props.dataTestid
|
|
92
100
|
}, {
|
|
101
|
+
prepend: withCtx(() => [__props.navigation ? (openBlock(), createBlock(unref(VAppBarNavIcon), {
|
|
102
|
+
key: 0,
|
|
103
|
+
"data-testid": navigationBtnDataTestid.value,
|
|
104
|
+
onClick: _cache[0] || (_cache[0] = ($event) => navigationOpen.value = !navigationOpen.value)
|
|
105
|
+
}, null, 8, ["data-testid"])) : createCommentVNode("v-if", true)]),
|
|
93
106
|
append: withCtx(() => [
|
|
94
107
|
showHelp.value ? (openBlock(), createBlock(unref(VBtn), mergeProps({ key: 0 }, unref(routeProps), {
|
|
95
108
|
"data-testid": helpBtnDataTestid.value,
|
|
@@ -98,7 +111,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
98
111
|
showNotifications.value ? (openBlock(), createBlock(unref(VMenu), {
|
|
99
112
|
key: 1,
|
|
100
113
|
modelValue: notificationsOpen.value,
|
|
101
|
-
"onUpdate:modelValue": _cache[
|
|
114
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => notificationsOpen.value = $event),
|
|
102
115
|
"close-on-content-click": false
|
|
103
116
|
}, {
|
|
104
117
|
activator: withCtx(({ props }) => [createVNode(unref(VBtn), mergeProps(props, {
|
|
@@ -118,7 +131,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
118
131
|
default: withCtx(() => [createVNode(unref(VCard), { "data-testid": notificationsMenuDataTestid.value }, {
|
|
119
132
|
default: withCtx(() => [props.notifications?.length ? (openBlock(), createBlock(unref(VList), { key: 0 }, {
|
|
120
133
|
default: withCtx(() => [createVNode(unref(VListSubheader), null, {
|
|
121
|
-
default: withCtx(() => [..._cache[
|
|
134
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Notificações", -1)])]),
|
|
122
135
|
_: 1
|
|
123
136
|
}), (openBlock(true), createElementBlock(Fragment, null, renderList(props.notifications, (notification, index) => {
|
|
124
137
|
return openBlock(), createBlock(unref(VListItem), {
|
|
@@ -130,7 +143,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
130
143
|
}, createSlots({ _: 2 }, [notification.date ? {
|
|
131
144
|
name: "append",
|
|
132
145
|
fn: withCtx(() => [createVNode(unref(VListItemAction), { end: "" }, {
|
|
133
|
-
default: withCtx(() => [createElementVNode("small", _hoisted_1, toDisplayString(formatNotificationDate(notification.date)), 1)]),
|
|
146
|
+
default: withCtx(() => [createElementVNode("small", _hoisted_1$1, toDisplayString(formatNotificationDate(notification.date)), 1)]),
|
|
134
147
|
_: 2
|
|
135
148
|
}, 1024)]),
|
|
136
149
|
key: "0"
|
|
@@ -142,7 +155,7 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
142
155
|
}), 128))]),
|
|
143
156
|
_: 1
|
|
144
157
|
})) : (openBlock(), createBlock(unref(VCardText), { key: 1 }, {
|
|
145
|
-
default: withCtx(() => [..._cache[
|
|
158
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode("Nenhuma notificação", -1)])]),
|
|
146
159
|
_: 1
|
|
147
160
|
}))]),
|
|
148
161
|
_: 1
|
|
@@ -202,6 +215,269 @@ var app_bar_default = /* @__PURE__ */ defineComponent({
|
|
|
202
215
|
}
|
|
203
216
|
});
|
|
204
217
|
//#endregion
|
|
218
|
+
//#region src/composables/inputs/rules.ts
|
|
219
|
+
function required(value) {
|
|
220
|
+
return !isEmpty(value) || "Campo obrigatório";
|
|
221
|
+
}
|
|
222
|
+
function phone(value) {
|
|
223
|
+
return isEmpty(value) || isPhone(value) || "Número inválido";
|
|
224
|
+
}
|
|
225
|
+
function email(value) {
|
|
226
|
+
return isEmpty(value) || isEmail(value) || "E-mail inválido";
|
|
227
|
+
}
|
|
228
|
+
function url(value) {
|
|
229
|
+
return isEmpty(value) || isUrl(value) || "URL inválida";
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/composables/inputs/use-rules.ts
|
|
233
|
+
function useRules(options) {
|
|
234
|
+
return computed(() => {
|
|
235
|
+
const rules = [];
|
|
236
|
+
if (options.required) rules.push(required);
|
|
237
|
+
return rules;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/composables/inputs/text-field.ts
|
|
242
|
+
const textFieldVariantToVuetifyVariant = {
|
|
243
|
+
primary: "underlined",
|
|
244
|
+
secondary: "outlined"
|
|
245
|
+
};
|
|
246
|
+
const textFieldTypeToVuetifyType = {
|
|
247
|
+
text: "text",
|
|
248
|
+
phone: "tel",
|
|
249
|
+
email: "email",
|
|
250
|
+
url: "url",
|
|
251
|
+
password: "password",
|
|
252
|
+
search: "text"
|
|
253
|
+
};
|
|
254
|
+
const textFieldTypeToVuetifyRule = {
|
|
255
|
+
phone,
|
|
256
|
+
email,
|
|
257
|
+
url
|
|
258
|
+
};
|
|
259
|
+
function useTextFieldVariant(variant) {
|
|
260
|
+
return computed(() => {
|
|
261
|
+
const variantValue = toValue(variant);
|
|
262
|
+
return textFieldVariantToVuetifyVariant[variantValue];
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function useTextFieldType(type) {
|
|
266
|
+
return computed(() => {
|
|
267
|
+
const typeValue = toValue(type);
|
|
268
|
+
return textFieldTypeToVuetifyType[typeValue];
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function useTextFieldRules(props) {
|
|
272
|
+
const defaultRules = useRules(props);
|
|
273
|
+
return computed(() => {
|
|
274
|
+
const rules = [...defaultRules.value];
|
|
275
|
+
const typeRule = associatedRuleType(props.type) ? textFieldTypeToVuetifyRule[props.type] : void 0;
|
|
276
|
+
if (typeRule) rules.push(typeRule);
|
|
277
|
+
return rules;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function associatedRuleType(type) {
|
|
281
|
+
return type in textFieldTypeToVuetifyRule;
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/components/inputs/text-field/text-field.vue
|
|
285
|
+
var text_field_default = /* @__PURE__ */ defineComponent({
|
|
286
|
+
inheritAttrs: false,
|
|
287
|
+
__name: "text-field",
|
|
288
|
+
props: /*@__PURE__*/ mergeModels({
|
|
289
|
+
variant: {
|
|
290
|
+
type: String,
|
|
291
|
+
required: false,
|
|
292
|
+
default: "primary"
|
|
293
|
+
},
|
|
294
|
+
type: {
|
|
295
|
+
type: String,
|
|
296
|
+
required: false,
|
|
297
|
+
default: "text"
|
|
298
|
+
},
|
|
299
|
+
disabled: {
|
|
300
|
+
type: Boolean,
|
|
301
|
+
required: false
|
|
302
|
+
},
|
|
303
|
+
loading: {
|
|
304
|
+
type: Boolean,
|
|
305
|
+
required: false
|
|
306
|
+
},
|
|
307
|
+
clearable: {
|
|
308
|
+
type: Boolean,
|
|
309
|
+
required: false,
|
|
310
|
+
default: void 0
|
|
311
|
+
},
|
|
312
|
+
readonly: {
|
|
313
|
+
type: Boolean,
|
|
314
|
+
required: false
|
|
315
|
+
},
|
|
316
|
+
required: {
|
|
317
|
+
type: Boolean,
|
|
318
|
+
required: false
|
|
319
|
+
},
|
|
320
|
+
label: {
|
|
321
|
+
type: String,
|
|
322
|
+
required: false
|
|
323
|
+
},
|
|
324
|
+
placeholder: {
|
|
325
|
+
type: String,
|
|
326
|
+
required: false
|
|
327
|
+
},
|
|
328
|
+
hint: {
|
|
329
|
+
type: String,
|
|
330
|
+
required: false
|
|
331
|
+
},
|
|
332
|
+
dataTestid: {
|
|
333
|
+
type: String,
|
|
334
|
+
required: false
|
|
335
|
+
}
|
|
336
|
+
}, {
|
|
337
|
+
"modelValue": {
|
|
338
|
+
type: String,
|
|
339
|
+
default: ""
|
|
340
|
+
},
|
|
341
|
+
"modelModifiers": {}
|
|
342
|
+
}),
|
|
343
|
+
emits: ["update:modelValue"],
|
|
344
|
+
setup(__props) {
|
|
345
|
+
const modelValue = useModel(__props, "modelValue");
|
|
346
|
+
const props = __props;
|
|
347
|
+
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
348
|
+
const vuetifyType = useTextFieldType(() => props.type);
|
|
349
|
+
const rules = useTextFieldRules(props);
|
|
350
|
+
const isSearchField = computed(() => props.type === "search");
|
|
351
|
+
const computedClearable = computed(() => props.clearable ?? isSearchField.value);
|
|
352
|
+
const prependIcon = computed(() => isSearchField.value ? "mdi-magnify" : void 0);
|
|
353
|
+
function clear() {
|
|
354
|
+
modelValue.value = "";
|
|
355
|
+
}
|
|
356
|
+
return (_ctx, _cache) => {
|
|
357
|
+
return openBlock(), createBlock(unref(VTextField), {
|
|
358
|
+
modelValue: modelValue.value,
|
|
359
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
|
360
|
+
variant: unref(vuetifyVariant),
|
|
361
|
+
type: unref(vuetifyType),
|
|
362
|
+
"prepend-inner-icon": prependIcon.value,
|
|
363
|
+
rules: unref(rules),
|
|
364
|
+
"data-testid": props.dataTestid,
|
|
365
|
+
disabled: props.disabled,
|
|
366
|
+
loading: props.loading,
|
|
367
|
+
readonly: props.readonly,
|
|
368
|
+
label: props.label,
|
|
369
|
+
placeholder: props.placeholder,
|
|
370
|
+
hint: props.hint,
|
|
371
|
+
clearable: computedClearable.value,
|
|
372
|
+
"onClick:clear": clear
|
|
373
|
+
}, null, 8, [
|
|
374
|
+
"modelValue",
|
|
375
|
+
"variant",
|
|
376
|
+
"type",
|
|
377
|
+
"prepend-inner-icon",
|
|
378
|
+
"rules",
|
|
379
|
+
"data-testid",
|
|
380
|
+
"disabled",
|
|
381
|
+
"loading",
|
|
382
|
+
"readonly",
|
|
383
|
+
"label",
|
|
384
|
+
"placeholder",
|
|
385
|
+
"hint",
|
|
386
|
+
"clearable"
|
|
387
|
+
]);
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region src/components/navigation-menu/navigation-menu.vue?vue&type=script&setup=true&lang.ts
|
|
393
|
+
const _hoisted_1 = { class: "px-4 pt-2" };
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/components/navigation-menu/navigation-menu.vue
|
|
396
|
+
var navigation_menu_default = /* @__PURE__ */ defineComponent({
|
|
397
|
+
inheritAttrs: false,
|
|
398
|
+
__name: "navigation-menu",
|
|
399
|
+
props: /*@__PURE__*/ mergeModels({
|
|
400
|
+
dataTestid: {
|
|
401
|
+
type: String,
|
|
402
|
+
required: false
|
|
403
|
+
},
|
|
404
|
+
items: {
|
|
405
|
+
type: Array,
|
|
406
|
+
required: false
|
|
407
|
+
}
|
|
408
|
+
}, {
|
|
409
|
+
"modelValue": {
|
|
410
|
+
type: Boolean,
|
|
411
|
+
default: false
|
|
412
|
+
},
|
|
413
|
+
"modelModifiers": {}
|
|
414
|
+
}),
|
|
415
|
+
emits: ["update:modelValue"],
|
|
416
|
+
setup(__props) {
|
|
417
|
+
const props = __props;
|
|
418
|
+
const open = useModel(__props, "modelValue");
|
|
419
|
+
const search = ref("");
|
|
420
|
+
const filteredItems = computed(() => filterItems());
|
|
421
|
+
const searchDataTestid = computed(() => `${props.dataTestid}-search`);
|
|
422
|
+
const query = computed(() => search.value.toLowerCase());
|
|
423
|
+
function filterItems() {
|
|
424
|
+
return (props.items ?? []).reduce((filtered, item) => {
|
|
425
|
+
if (matches(item)) filtered.push(item);
|
|
426
|
+
else if (isParentItem(item)) {
|
|
427
|
+
const matchingChildren = item.items.filter((child) => matches(child));
|
|
428
|
+
if (matchingChildren.length) filtered.push({
|
|
429
|
+
...item,
|
|
430
|
+
items: matchingChildren
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
return filtered;
|
|
434
|
+
}, []);
|
|
435
|
+
}
|
|
436
|
+
function matches(item) {
|
|
437
|
+
return item.description.toLowerCase().includes(query.value);
|
|
438
|
+
}
|
|
439
|
+
function isParentItem(item) {
|
|
440
|
+
return "items" in item;
|
|
441
|
+
}
|
|
442
|
+
return (_ctx, _cache) => {
|
|
443
|
+
return openBlock(), createBlock(unref(VNavigationDrawer), {
|
|
444
|
+
modelValue: open.value,
|
|
445
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => open.value = $event),
|
|
446
|
+
"data-testid": props.dataTestid,
|
|
447
|
+
absolute: "",
|
|
448
|
+
temporary: ""
|
|
449
|
+
}, {
|
|
450
|
+
prepend: withCtx(() => [createElementVNode("div", _hoisted_1, [createVNode(text_field_default, {
|
|
451
|
+
modelValue: search.value,
|
|
452
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => search.value = $event),
|
|
453
|
+
type: "search",
|
|
454
|
+
label: "Buscar",
|
|
455
|
+
"data-testid": searchDataTestid.value
|
|
456
|
+
}, null, 8, ["modelValue", "data-testid"])])]),
|
|
457
|
+
default: withCtx(() => [createVNode(unref(VDivider)), createVNode(unref(VList), { nav: "" }, {
|
|
458
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filteredItems.value, (item, index) => {
|
|
459
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [isParentItem(item) ? (openBlock(), createBlock(unref(VListGroup), { key: 0 }, {
|
|
460
|
+
activator: withCtx(({ props: activatorProps }) => [createVNode(unref(VListItem), mergeProps({ ref_for: true }, activatorProps, { title: item.description }), null, 16, ["title"])]),
|
|
461
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(item.items, (childItem, childIndex) => {
|
|
462
|
+
return openBlock(), createBlock(unref(VListItem), mergeProps({ key: childIndex }, { ref_for: true }, unref(routeToProps)(childItem.route), {
|
|
463
|
+
title: childItem.description,
|
|
464
|
+
onClick: childItem.action
|
|
465
|
+
}), null, 16, ["title", "onClick"]);
|
|
466
|
+
}), 128))]),
|
|
467
|
+
_: 2
|
|
468
|
+
}, 1024)) : (openBlock(), createBlock(unref(VListItem), mergeProps({
|
|
469
|
+
key: 1,
|
|
470
|
+
title: item.description
|
|
471
|
+
}, { ref_for: true }, unref(routeToProps)(item.route), { onClick: item.action }), null, 16, ["title", "onClick"]))], 64);
|
|
472
|
+
}), 128))]),
|
|
473
|
+
_: 1
|
|
474
|
+
})]),
|
|
475
|
+
_: 1
|
|
476
|
+
}, 8, ["modelValue", "data-testid"]);
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
//#endregion
|
|
205
481
|
//#region src/components/grid/container/container.vue
|
|
206
482
|
var container_default = /* @__PURE__ */ defineComponent({
|
|
207
483
|
inheritAttrs: false,
|
|
@@ -264,6 +540,10 @@ var root_default = /* @__PURE__ */ defineComponent({
|
|
|
264
540
|
appBar: {
|
|
265
541
|
type: Object,
|
|
266
542
|
required: false
|
|
543
|
+
},
|
|
544
|
+
navigationMenu: {
|
|
545
|
+
type: Object,
|
|
546
|
+
required: false
|
|
267
547
|
}
|
|
268
548
|
}, {
|
|
269
549
|
"notificationsOpen": {
|
|
@@ -275,19 +555,33 @@ var root_default = /* @__PURE__ */ defineComponent({
|
|
|
275
555
|
emits: ["update:notificationsOpen"],
|
|
276
556
|
setup(__props) {
|
|
277
557
|
const props = __props;
|
|
558
|
+
const appBarProps = computed(() => props.appBar ? {
|
|
559
|
+
...props.appBar,
|
|
560
|
+
navigation: props.navigationMenu !== void 0
|
|
561
|
+
} : void 0);
|
|
278
562
|
const notificationsOpen = useModel(__props, "notificationsOpen");
|
|
563
|
+
const navigationMenuOpen = ref(false);
|
|
279
564
|
return (_ctx, _cache) => {
|
|
280
565
|
return openBlock(), createBlock(unref(VApp), { "data-testid": props.dataTestid }, {
|
|
281
|
-
default: withCtx(() => [
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
566
|
+
default: withCtx(() => [
|
|
567
|
+
appBarProps.value ? (openBlock(), createBlock(app_bar_default, mergeProps({ key: 0 }, appBarProps.value, {
|
|
568
|
+
"notifications-open": notificationsOpen.value,
|
|
569
|
+
"onUpdate:notificationsOpen": _cache[0] || (_cache[0] = ($event) => notificationsOpen.value = $event),
|
|
570
|
+
"navigation-open": navigationMenuOpen.value,
|
|
571
|
+
"onUpdate:navigationOpen": _cache[1] || (_cache[1] = ($event) => navigationMenuOpen.value = $event)
|
|
572
|
+
}), null, 16, ["notifications-open", "navigation-open"])) : createCommentVNode("v-if", true),
|
|
573
|
+
props.navigationMenu ? (openBlock(), createBlock(navigation_menu_default, mergeProps({ key: 1 }, props.navigationMenu, {
|
|
574
|
+
modelValue: navigationMenuOpen.value,
|
|
575
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => navigationMenuOpen.value = $event)
|
|
576
|
+
}), null, 16, ["modelValue"])) : createCommentVNode("v-if", true),
|
|
577
|
+
createVNode(unref(VMain), null, {
|
|
578
|
+
default: withCtx(() => [createVNode(container_default, null, {
|
|
579
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default"), createVNode(toast_default)]),
|
|
580
|
+
_: 3
|
|
581
|
+
})]),
|
|
287
582
|
_: 3
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
})]),
|
|
583
|
+
})
|
|
584
|
+
]),
|
|
291
585
|
_: 3
|
|
292
586
|
}, 8, ["data-testid"]);
|
|
293
587
|
};
|
|
@@ -386,170 +680,6 @@ var btn_default = /* @__PURE__ */ defineComponent({
|
|
|
386
680
|
}
|
|
387
681
|
});
|
|
388
682
|
//#endregion
|
|
389
|
-
//#region src/composables/inputs/rules.ts
|
|
390
|
-
function required(value) {
|
|
391
|
-
return !isEmpty(value) || "Campo obrigatório";
|
|
392
|
-
}
|
|
393
|
-
function phone(value) {
|
|
394
|
-
return isEmpty(value) || isPhone(value) || "Número inválido";
|
|
395
|
-
}
|
|
396
|
-
function email(value) {
|
|
397
|
-
return isEmpty(value) || isEmail(value) || "E-mail inválido";
|
|
398
|
-
}
|
|
399
|
-
function url(value) {
|
|
400
|
-
return isEmpty(value) || isUrl(value) || "URL inválida";
|
|
401
|
-
}
|
|
402
|
-
//#endregion
|
|
403
|
-
//#region src/composables/inputs/use-rules.ts
|
|
404
|
-
function useRules(options) {
|
|
405
|
-
return computed(() => {
|
|
406
|
-
const rules = [];
|
|
407
|
-
if (options.required) rules.push(required);
|
|
408
|
-
return rules;
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
//#endregion
|
|
412
|
-
//#region src/composables/inputs/text-field.ts
|
|
413
|
-
const textFieldVariantToVuetifyVariant = {
|
|
414
|
-
primary: "underlined",
|
|
415
|
-
secondary: "outlined"
|
|
416
|
-
};
|
|
417
|
-
const textFieldTypeToVuetifyType = {
|
|
418
|
-
text: "text",
|
|
419
|
-
phone: "tel",
|
|
420
|
-
email: "email",
|
|
421
|
-
url: "url",
|
|
422
|
-
password: "password",
|
|
423
|
-
search: "text"
|
|
424
|
-
};
|
|
425
|
-
const textFieldTypeToVuetifyRule = {
|
|
426
|
-
phone,
|
|
427
|
-
email,
|
|
428
|
-
url
|
|
429
|
-
};
|
|
430
|
-
function useTextFieldVariant(variant) {
|
|
431
|
-
return computed(() => {
|
|
432
|
-
const variantValue = toValue(variant);
|
|
433
|
-
return variantValue ? textFieldVariantToVuetifyVariant[variantValue] : textFieldVariantToVuetifyVariant.primary;
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
function useTextFieldType(type) {
|
|
437
|
-
return computed(() => {
|
|
438
|
-
const typeValue = toValue(type);
|
|
439
|
-
return typeValue ? textFieldTypeToVuetifyType[typeValue] : textFieldTypeToVuetifyType.text;
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
function useTextFieldRules(props) {
|
|
443
|
-
const defaultRules = useRules(props);
|
|
444
|
-
return computed(() => {
|
|
445
|
-
const rules = [...defaultRules.value];
|
|
446
|
-
const typeRule = associatedRuleType(props.type) ? textFieldTypeToVuetifyRule[props.type] : void 0;
|
|
447
|
-
if (typeRule) rules.push(typeRule);
|
|
448
|
-
return rules;
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
function associatedRuleType(type) {
|
|
452
|
-
return type in textFieldTypeToVuetifyRule;
|
|
453
|
-
}
|
|
454
|
-
//#endregion
|
|
455
|
-
//#region src/components/inputs/text-field/text-field.vue
|
|
456
|
-
var text_field_default = /* @__PURE__ */ defineComponent({
|
|
457
|
-
inheritAttrs: false,
|
|
458
|
-
__name: "text-field",
|
|
459
|
-
props: /*@__PURE__*/ mergeModels({
|
|
460
|
-
variant: {
|
|
461
|
-
type: String,
|
|
462
|
-
required: false
|
|
463
|
-
},
|
|
464
|
-
type: {
|
|
465
|
-
type: String,
|
|
466
|
-
required: false
|
|
467
|
-
},
|
|
468
|
-
disabled: {
|
|
469
|
-
type: Boolean,
|
|
470
|
-
required: false
|
|
471
|
-
},
|
|
472
|
-
loading: {
|
|
473
|
-
type: Boolean,
|
|
474
|
-
required: false
|
|
475
|
-
},
|
|
476
|
-
clearable: {
|
|
477
|
-
type: Boolean,
|
|
478
|
-
required: false,
|
|
479
|
-
default: () => void 0
|
|
480
|
-
},
|
|
481
|
-
readonly: {
|
|
482
|
-
type: Boolean,
|
|
483
|
-
required: false
|
|
484
|
-
},
|
|
485
|
-
required: {
|
|
486
|
-
type: Boolean,
|
|
487
|
-
required: false
|
|
488
|
-
},
|
|
489
|
-
label: {
|
|
490
|
-
type: String,
|
|
491
|
-
required: false
|
|
492
|
-
},
|
|
493
|
-
placeholder: {
|
|
494
|
-
type: String,
|
|
495
|
-
required: false
|
|
496
|
-
},
|
|
497
|
-
hint: {
|
|
498
|
-
type: String,
|
|
499
|
-
required: false
|
|
500
|
-
},
|
|
501
|
-
dataTestid: {
|
|
502
|
-
type: String,
|
|
503
|
-
required: false
|
|
504
|
-
}
|
|
505
|
-
}, {
|
|
506
|
-
"modelValue": {
|
|
507
|
-
type: String,
|
|
508
|
-
default: ""
|
|
509
|
-
},
|
|
510
|
-
"modelModifiers": {}
|
|
511
|
-
}),
|
|
512
|
-
emits: ["update:modelValue"],
|
|
513
|
-
setup(__props) {
|
|
514
|
-
const modelValue = useModel(__props, "modelValue");
|
|
515
|
-
const props = createPropsRestProxy(__props, ["clearable"]);
|
|
516
|
-
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
517
|
-
const vuetifyType = useTextFieldType(() => props.type);
|
|
518
|
-
const rules = useTextFieldRules(props);
|
|
519
|
-
const computedClearable = computed(() => __props.clearable ?? props.type === "search");
|
|
520
|
-
return (_ctx, _cache) => {
|
|
521
|
-
return openBlock(), createBlock(unref(VTextField), {
|
|
522
|
-
modelValue: modelValue.value,
|
|
523
|
-
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
|
524
|
-
variant: unref(vuetifyVariant),
|
|
525
|
-
type: unref(vuetifyType),
|
|
526
|
-
rules: unref(rules),
|
|
527
|
-
"data-testid": props.dataTestid,
|
|
528
|
-
disabled: props.disabled,
|
|
529
|
-
loading: props.loading,
|
|
530
|
-
readonly: props.readonly,
|
|
531
|
-
label: props.label,
|
|
532
|
-
placeholder: props.placeholder,
|
|
533
|
-
hint: props.hint,
|
|
534
|
-
clearable: computedClearable.value
|
|
535
|
-
}, null, 8, [
|
|
536
|
-
"modelValue",
|
|
537
|
-
"variant",
|
|
538
|
-
"type",
|
|
539
|
-
"rules",
|
|
540
|
-
"data-testid",
|
|
541
|
-
"disabled",
|
|
542
|
-
"loading",
|
|
543
|
-
"readonly",
|
|
544
|
-
"label",
|
|
545
|
-
"placeholder",
|
|
546
|
-
"hint",
|
|
547
|
-
"clearable"
|
|
548
|
-
]);
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
//#endregion
|
|
553
683
|
//#region src/components/grid/row/row.vue
|
|
554
684
|
var row_default = /* @__PURE__ */ defineComponent({
|
|
555
685
|
inheritAttrs: false,
|
package/dist/unit-test.js
CHANGED
|
@@ -16,7 +16,7 @@ const vuetify = createVuetify({
|
|
|
16
16
|
* Vue Test Utils plugin for Uimed.
|
|
17
17
|
*/
|
|
18
18
|
function vueTestUtilsPluginUimed() {
|
|
19
|
-
|
|
19
|
+
globalThis.ResizeObserver = __require("resize-observer-polyfill");
|
|
20
20
|
return vuetify;
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexdom/uimed-vue",
|
|
3
|
-
"version": "1.2.0-beta.
|
|
3
|
+
"version": "1.2.0-beta.3",
|
|
4
4
|
"description": "A ui framework for NEXDOM applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lib",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
-
"AGENTS.md"
|
|
25
|
+
"AGENTS.md",
|
|
26
|
+
"CLAUDE.md"
|
|
26
27
|
],
|
|
27
28
|
"type": "module",
|
|
28
29
|
"exports": {
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"@mdi/font": "^7.4.47",
|
|
59
60
|
"@nexdom/shared": "^2.1.1",
|
|
60
61
|
"@playwright/test": "^1.62.1",
|
|
62
|
+
"@sonar/scan": "^5.0.0",
|
|
61
63
|
"@stryker-mutator/core": "^10.0.0",
|
|
62
64
|
"@stryker-mutator/vitest-runner": "^10.0.0",
|
|
63
65
|
"@types/node": "^26.1.2",
|